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

MSVC发现这个方法调用不明确是正确的,而Clang/GCC没有?

艾弘义
2023-03-14

运行此代码时,Clang(3.9.1)和GCC(7,快照)将“1”、“2”打印到控制台。

但是,MSVC未能编译此代码:

source_file.cpp(15):错误C2668:字典::集:对重载函数的模糊调用

source_file.cpp(9):注意:可能是“无效字典::集(int64_t)”

source_file.cpp(8):注意:或'无效字典::集(const char*)'

源文件。cpp(15):注意:在尝试匹配参数列表(const unsigned int)时

#include <iostream>

static const unsigned ProtocolMajorVersion = 1;
static const unsigned ProtocolMinorVersion = 0;

class Dictionary {
public:
    void set(const char *Str) { std::cout << "1"; }
    void set(int64_t val) { std::cout << "2"; }
};

int main() {
    Dictionary dict;
    dict.set(ProtocolMajorVersion);
    dict.set(ProtocolMinorVersion);
}

我认为MSVC是正确的,ProtocolMajorVersion的值是0,它可以是NULLint64\u t(0)

然而,在更换时似乎就是这样

dict.set(ProtocolMinorVersion)

具有

dict.set(0);

source_file.cpp:15: 10:错误:调用成员函数'set'不明确dict.set(0);

source_file.cpp: 8:10:注:候选函数

void set(const char *Str) { std::cout << "1"; }

源文件。cpp:9:10:注:候选函数

void set(int64_t val) { std::cout << "2"; }

那么这里发生了什么-哪个编译器是正确的?如果GCC和Clang都接受不正确的代码,或者MSVC只是有缺陷,我会感到惊讶吗?请参考标准

共有2个答案

慕弘义
2023-03-14

当两个编译器同意而一个不同意时,几乎总是那个不同意的编译器错了。

我认为,如果您将一个值声明为const unsigned somename=0 ,它不再是一个简单的零,而是一个值为零的命名无符号常量。因此,不应将其视为等同于指针类型,只留下一个看似合理的候选者。

话虽如此,两个set函数都需要转换(它不是uint64\t,也不是const char*),因此,有人可能会认为MSVC是正确的[编译器应该选择需要最少转换的类型,如果多个类型需要相等的转换量,那么这是不明确的]——尽管我仍然认为编译器不应该接受值为零的命名常量作为指针的等价物。。。

对不起,可能更多的是一个“评论”而不是一个答案——我开始写作的目的是说“gcc/clang是正确的”,但后来仔细思考后得出结论,“虽然我会更喜欢这种行为,但不清楚这是否是正确的行为”。

宇文峰
2023-03-14

在C11及之前,任何计算为0的积分常量表达式都被认为是空指针常量。这在C14中受到限制:只考虑值为0的整数文字。此外,类型std::nullptr_t的prvalue是自C 11以来的空指针常量。参见[conv.ptr]和CWG 903。

关于重载分辨率,整数转换无符号-

因此,如果原型MinorVersion被认为是空指针常量,那么调用是不明确的。如果你只是编译以下程序:

static const unsigned ProtocolMinorVersion = 0;

int main() {
    const char* p = ProtocolMinorVersion;
}

您将看到,clang和gcc拒绝此转换,而MSVC接受此转换。

由于CWG903被认为是一个缺陷,我认为clang和gcc是正确的。

 类似资料:
  • 我有带转换操作符的简单代码,似乎所有的编译器都给出不同的结果,我很好奇哪个编译器是正确的?我也尝试了不同的组合,但以下是最有趣的。代码是使用C 11标志编译的,但是在C 03中也可能观察到相同的行为。 叮当声-3.6: g -4.9: msvc 2014年CTP: 删除后: msvc编译: 此外,在移除const in后 叮当声-3.6: g -4.9: msvc 2014年CTP:

  • 问题内容: 我读这个和这个,结果发现,在课堂上我需要保存到类的引用,当东西在发生类,我们执行由类的接口中定义的方法工具。好吧,我明白了。我以不同的方式使用接口来调用回调: 我发现这种方式更具可读性,更容易理解,但是不确定这是否是不好的做法。因此,我可以随意走这条路吗? 问题答案: 所以我可以随意走这条路吗? 这种方式不是很正确。 您在说的是称为Observer或/ 模式。 简而言之:订户想要从发布

  • 我读了这篇文章和这篇文章,发现在类中,我需要保存对类的引用,当类中发生一些事情时,我们执行一个由类实现的接口定义的方法。不知何故我明白了。我以不同的方式使用接口来调用回调: 我发现这种方式更易读,更容易理解,但不确定这是否是一个不好的做法。所以我可以自由地走得更远吗?

  • 问题内容: 我能够使用三个链接来组合一个简化的完整History.js示例,以从整个页面加载内容片段,而无需更新页面和更新浏览器历史记录。 这是相关的代码段- 完整的工作示例在此处http://jsfiddle.net/PT7qx/show 我想知道这是否正确。以前的版本可以使用#url绑定到事件。我没有看到使用此最新版本将事件绑定到url的任何示例,因此我使用了.on()click事件来调用Hi

  • 在使用检测习惯用法和< code>void_t时,我发现包含减法运算符和void*的表达式会在测试的编译器中导致不同的错误。 GCC 10.2及以下,无论是否使用C 11、14、17或20,似乎都将某些表达式视为硬错误,而不是替换失败。 我正在使用以下(条带化)示例 并且希望代码能够针对所有四种语言标准编译无误(包含对C 17之前版本的< code>std::void_t替换,因此可以测试更多的标

  • 假设我们有以下简单的代码: 这段代码使用clang编译并打印“T”,但使用gcc我们有以下错误: 我的问题是哪个编译器有bug,gcc还是叮当声?