当前位置: 首页 > 知识库问答 >
问题:

原子函数指针调用可以在gcc中编译,但不能在clang和msvc中编译

颜修明
2023-03-14

从原子函数指针调用函数时,如:

#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的对象

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

  • operator\uuuu pointer\u type()const noexcept
  • operator\uuuu pointer\u type()常量volatile noexcept

波动性的这种差异似乎让clang和msvc感到困惑,但海湾合作委员会却没有。

当调用从f()更改为f.load()。这就更让人困惑了,因为load()operator T()都有constconst volatile重载——如果隐式转换不起作用,我希望load()也不会起作用。隐式转换(与成员调用)中的规则是否有所不同?

那么,gcc接受该代码是错误的吗?clang和msvc出错了吗?还有其他错误或正确的组合吗?

如果有一个原子指针,我想知道一个更好的方法。


共有1个答案

季小云
2023-03-14
匿名用户

Clang和MSVC是正确的。

对于每个转换函数到类的函数指针,一个所谓的代理调用函数被添加到重载解析,如果选择,它将首先通过这个运算符重载将对象转换为函数指针,然后通过函数指针调用函数。这在[over.call.object]/2中解释。

但是,代理调用函数不会以任何方式转换转换运算符的cv限定符。因此,由于std::atomic有一个转换运算符是volatile和一个不是volatile,因此将有两个不可区分的代理调用函数。由于std::atomic没有任何实际的运算符(),因此重载解析必须始终是不明确的,因此它们也是唯一的候选对象。

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

直接调用。load()volatile-限定符将在重载解析中起到平衡作用,因此不会出现此问题。

使用(内置)运算符*上的(*f)()重载解析以函数指针类型为参数执行。通过两个转换函数有两个隐式转换序列。标准不是很清楚,但我认为目的是这不会导致不明确的转换序列(当选择它时,这也意味着不明确的重载解析)。相反,我认为它的目的是应用转换函数初始化的规则来选择其中一个转换,这将使其明确成为易失性限定的转换。

 类似资料:
  • 下面的代码在g7.2.0中编译成功(编译标志是),但在clang 5.0.0中编译失败(使用相同的标志,)和vc 15.4(编译标志是): 哪种编译器行为符合标准?如何将该模板应用更改为在clang上编译? 叮当声错误消息: VC错误消息:

  • 问题内容: 注意:这是从Comparable和Comparator合约衍生出来的,涉及null 该代码可以在Eclipse(20090920-1017)中编译并正常运行 但是它不能在上编译javac 1.6.0_17。这是错误消息: 有人可以解释为什么差异吗?这是一个错误吗?如果是这样,谁有错误? 问题答案: 这是一个已确认的错误:错误ID 6468354。这是相关的摘录: 此问题是由以下事实引起

  • 问题内容: 我不得不发现我的项目中有Java代码,该代码可以在Eclipse中编译并正常运行,但是会在javac中引发编译错误。 一个完整的代码段: javac中的编译返回: 现在,此错误阻止在Maven中构建项目。由于Eclipse编译器具有更高的容忍度,因此我现在不得不假设代码段的定义和用法如上所述,静态方法不是有效的Java吗? 问题答案: 似乎Sun的1.6 JDK无法推断正确的类型。以下

  • 问题内容: 说,我想在gcc的内联汇编中调用具有以下签名的函数。我怎样才能做到这一点? 问题答案: 通常,您会想要做类似的事情 也就是说,您根本不需要在嵌入式asm中进行函数调用。这样,您不必担心调用约定或堆栈框架管理的细节。

  • 我有一个小函数,它使用从创建一个日期对象,而在ubuntu下使用clang或gcc进行编译,而在windows下不使用msvc。 对于每个调用在编译时显示以下错误: 'std::from_chars':14个重载都不能转换所有参数类型 然后,编译器继续列出可能的重载,我清楚地看到了我试图使用的重载: 'std::from_chars_resultstd::from_chars(const char

  • 问题内容: 抱歉,标题含糊。我有这段代码可以在Eclipse Juno(4.2)上编译,但不能在javac(1.7.0_09)上编译: 错误是: 所以问题是: 这是Bug还是Eclipse错误? 有什么办法可以在不更改方法签名的情况下进行编译(即保留通配符)? 我知道将其更改为确实可以使其编译,但是我想知道是否有办法首先避免这种情况。另外,由于内容的类型需要严格的约束,因此无法将方法更改为。 问题