繁体   English   中英

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

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

从原子 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 根本没有抱怨,而 clang 和 msvc 在调用f()时有问题:

  • [clang]:错误:调用类型为“std::atomic<func_type>”(又名“atomic<int (*)()>”)的 object 不明确
  • [msvc]:有不止一种方法可以为参数列表调用类型为“std::atomic<func_type>”的 object

Clang 还指定可能的呼叫候选者为:

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

似乎这种波动性差异对 clang 和 msvc 造成了混淆,但对 gcc 却没有。

当调用从f()更改为f.load()()时,代码适用于所有上述编译器。 这更令人困惑,因为据说load()operator T()都具有constconst volatile重载——如果隐式转换不起作用,我预计load()也不会起作用。 隐式转换(相对于成员调用)中的规则是否有所不同?

那么,gcc 接受该代码是错误的吗? clang 和 msvc 是不是都错报错了? 任何其他错误或正确的组合?


这主要是一个理论问题,但如果有更好的方法来获得原子 function 指针,我想知道。

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 . 这在[over.call.object]/2中有解释。

但是,代理调用 function 不会以任何方式转换转换运算符的 cv 限定符。 因此,由于std::atomic有一个转换运算符,一个是volatile一个不是,因此将有两个无法区分的代理调用函数。 这些也是唯一的候选者,因为std::atomic没有任何实际的operator()并且因此重载决策必须始终是模棱两可的。

标准中甚至有一个脚注提到这可能发生,请参阅[over.call.object]/footnote.120

通过直接调用.load()volatile -qualifier 将成为重载解决方案中的决胜局,因此不会出现此问题。

使用(*f)()对(内置) operator*执行重载决策,指针类型为 function 作为参数。 通过两个转换函数有两个隐式转换序列。 标准对此不是很清楚,但我认为其意图是这不会导致不明确的转换序列(这也意味着在选择时不明确的重载解析)。 相反,我认为通过转换 function 进行初始化的规则仅应用于 select 转换之一,这将使它明确地成为volatile限定的转换。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM