[英]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 还指定可能的呼叫候选者为:
operator __pointer_type() const noexcept
operator __pointer_type() const volatile noexcept
似乎这种波动性差异对 clang 和 msvc 造成了混淆,但对 gcc 却没有。
当调用从f()
更改为f.load()()
时,代码适用于所有上述编译器。 这更令人困惑,因为据说load()
和operator T()
都具有const
和const 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.