ja2*_*142 18 c++ atomic language-lawyer stdatomic
当从原子函数指针调用函数时,例如:
#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();
}
Run Code Online (Sandbox Code Playgroud)
gcc 根本不抱怨,而 clang 和 msvc 在调用方面有问题f():
Clang 还指定了可能的候选调用:
operator __pointer_type() const noexceptoperator __pointer_type() const volatile noexcept看起来这种波动性的差异对于 clang 和 msvc 来说是令人困惑的,但对于 gcc 却不是。
f()当 call从改为 时f.load()(),代码可以在所有上述编译器中运行。这更令人困惑,因为据说load()和都有和重载 - 如果隐式转换不起作用,我预计也不会起作用。隐式转换(与成员调用)中的规则是否有所不同?operator T()constconst volatileload()
那么,gcc 接受该代码是错误的吗?clang和msvc错误会报错吗?还有其他错误或正确的组合吗?
这主要是一个理论问题,但如果有更好的方法来拥有原子函数指针,我想知道。
use*_*522 19
Clang 和 MSVC 是正确的。
对于每个到类的函数指针的转换函数,都会将所谓的代理调用函数添加到重载决策中,如果选择该函数,将首先通过此运算符重载将对象转换为函数指针,然后通过函数指针调用该函数。这在[over.call.object]/2中进行了解释。
但是,代理调用函数不会以任何方式转换转换运算符的 cv 限定符。因此,由于std::atomic有一个转换运算符,一个是volatile,一个不是,因此将存在两个无法区分的代理调用函数。这些也是唯一的候选者,因为std::atomic没有任何实际的operator(),因此重载解析必须始终是不明确的。
标准中甚至有一个脚注提到这种情况可能会发生,请参阅[over.call.object]/footnote.120。
直接调用.load()-qualifiervolatile将成为重载决策中的决定性因素,因此不会出现此问题。
使用函数指针类型作为参数(*f)()对(内置)进行重载解析。operator*通过两个转换函数有两个隐式转换序列。标准对此不是很清楚,但我认为这样做的目的是,这不会导致不明确的转换序列(这也意味着选择时的重载解析不明确)。相反,我认为转换函数初始化的规则旨在仅选择其中一种转换,这将使其明确成为 -volatile限定的转换。
| 归档时间: |
|
| 查看次数: |
1082 次 |
| 最近记录: |