简体   繁体   English

原子 function 指针调用在 gcc 中编译,但在 clang 和 msvc 中不编译

[英]Atomic function pointer call compiles in gcc, but not in clang and msvc

When calling function from an atomic function pointer, like:从原子 function 指针调用 function 时,如:

#include <atomic>
#include <type_traits>

int func0(){ return 0; }

using func_type = std::add_pointer<int()>::type;

std::atomic<func_type> f = { func0 };

int main(){
        f();
}

gcc doesn't complain at all, while clang and msvc have problem with call f() : gcc 根本没有抱怨,而 clang 和 msvc 在调用f()时有问题:

  • [clang]: error: call to object of type 'std::atomic<func_type>' (aka 'atomic<int (*)()>') is ambiguous [clang]:错误:调用类型为“std::atomic<func_type>”(又名“atomic<int (*)()>”)的 object 不明确
  • [msvc]: there is more than one way an object of type "std::atomic<func_type>" can be called for the argument list [msvc]:有不止一种方法可以为参数列表调用类型为“std::atomic<func_type>”的 object

Clang additionally specifies possible call candidates to be: Clang 还指定可能的呼叫候选者为:

  • operator __pointer_type() const noexcept
  • operator __pointer_type() const volatile noexcept

It seems like this difference in volatility is confusing for clang and msvc, but not gcc.似乎这种波动性差异对 clang 和 msvc 造成了混淆,但对 gcc 却没有。

When call is changed from f() to f.load()() , the code works in all abovementioned compilers.当调用从f()更改为f.load()()时,代码适用于所有上述编译器。 Which is all the more confusing, since both load() and operator T() are said to have const and const volatile overloads - if implicit conversion doesn't work, I'd expect load() not to work as well.这更令人困惑,因为据说load()operator T()都具有constconst volatile重载——如果隐式转换不起作用,我预计load()也不会起作用。 Are the rules somehow different within implicit conversions (versus member calls)?隐式转换(相对于成员调用)中的规则是否有所不同?

So, is gcc wrong to accept that code?那么,gcc 接受该代码是错误的吗? Are clang and msvc wrong to error out? clang 和 msvc 是不是都错报错了? Any other combination of being wrong or right?任何其他错误或正确的组合?


This is mostly a theoretical question, but if there is some better way to have an atomic function pointer, I'd like to know.这主要是一个理论问题,但如果有更好的方法来获得原子 function 指针,我想知道。

Clang and MSVC are correct. Clang 和 MSVC 是正确的。

For each conversion function to a function pointer of the class, a so-called surrogate call function is added to overload resolution, which if chosen would first convert the object via this operator overload to a function pointer and then call the function via the function pointer. For each conversion function to a function pointer of the class, a so-called surrogate call function is added to overload resolution, which if chosen would first convert the object via this operator overload to a function pointer and then call the function via the function pointer . This is explained in [over.call.object]/2 .这在[over.call.object]/2中有解释。

However, the surrogate call function does not translate the cv-qualifiers of the conversion operator in any way.但是,代理调用 function 不会以任何方式转换转换运算符的 cv 限定符。 So, since std::atomic has a conversion operator which is volatile and one which is not, there will be two indistinguishable surrogate call functions.因此,由于std::atomic有一个转换运算符,一个是volatile一个不是,因此将有两个无法区分的代理调用函数。 These are also the only candidates since std::atomic doesn't have any actual operator() and so overload resolution must always be ambiguous.这些也是唯一的候选者,因为std::atomic没有任何实际的operator()并且因此重载决策必须始终是模棱两可的。

There is even a footnote in the standard mentioning that this can happen, see [over.call.object]/footnote.120 .标准中甚至有一个脚注提到这可能发生,请参阅[over.call.object]/footnote.120

With a direct call to .load() the volatile -qualifier will be a tie-breaker in overload resolution, so this issue doesn't appear.通过直接调用.load()volatile -qualifier 将成为重载解决方案中的决胜局,因此不会出现此问题。

With (*f)() overload resolution on the (built-in) operator* with the function pointer type as parameter is performed.使用(*f)()对(内置) operator*执行重载决策,指针类型为 function 作为参数。 There are two implicit conversion sequences via the two conversion functions.通过两个转换函数有两个隐式转换序列。 The standard isn't very clear on it, but I think the intention is that this doesn't result in an ambiguous conversion sequence (which would also imply ambiguous overload resolution when it is chosen).标准对此不是很清楚,但我认为其意图是这不会导致不明确的转换序列(这也意味着在选择时不明确的重载解析)。 Instead I think it is intended that the rules for initialization by conversion function are applied to select only one of the conversions, which would make it unambiguously the volatile -qualified one.相反,我认为通过转换 function 进行初始化的规则仅应用于 select 转换之一,这将使它明确地成为volatile限定的转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 operator== 使用 msvc 编译,但不使用 gcc 和 clang - operator== compiles with msvc but not with gcc and clang gcc和clang抛出“没有匹配的函数调用”,但msvc(cl)编译并按预期工作 - gcc and clang throw “no matching function call” but msvc (cl) compiles and works as expected 模棱两可的 function 在 msvc 和 clang 中调用,但在 gcc 中不调用 - Ambiguous function call in msvc and clang but not in gcc 海湾合作委员会声称一个朋友的功能是超载,暧昧的电话,铿锵编译 - GCC claims a friend function to be overloaded, ambiguous call, clang compiles gcc vs. clang,msvc和icc:这个函数调用不明确吗? - gcc vs. clang, msvc and icc: Is this function call ambiguous? 在clang vs gcc和msvc中按方法指针的模板 - Template by method pointer in clang vs gcc and msvc MSVC:无法识别的模板声明/定义(与Clang / GCC编译) - MSVC: unrecognizable template declaration/definition (compiles with Clang/GCC) 编译类型模板谓词使用Clang编译,但不与GCC或MSVC编译 - A compile-type template predicate compiles with Clang, but not with GCC or MSVC Clang 14 和 15 显然优化了在 Clang 下按预期编译的代码 13,ICC,GCC,MSVC - Clang 14 and 15 apparently optimizing away code that compiles as expected under Clang 13, ICC, GCC, MSVC 值模板化方法的std :: function可使用clang和g ++编译,但不能使用msvc编译 - std::function of a value templated method compiles with clang and g++ but not with msvc
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM