H B*_*amy 3 c++ gcc clang visual-c++ language-lawyer
运行此代码时,Clang (3.9.1) 和 GCC (7, snapshot) 将“1”、“2”打印到控制台。
但是,MSVC 无法编译此代码:
source_file.cpp(15):错误 C2668:'Dictionary::set':对重载函数的调用不明确
source_file.cpp(9):注意:可能是'void Dictionary::set(int64_t)'
source_file.cpp(8): 注意:或 'void Dictionary::set(const char *)'
source_file.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);
}
Run Code Online (Sandbox Code Playgroud)
我认为MSVC是正确的-的价值ProtocolMajorVersion是0,它可以是NULL或int64_t(0)。
但是,更换时似乎是这种情况
dict.set(ProtocolMinorVersion)
Run Code Online (Sandbox Code Playgroud)
和
dict.set(0);
Run Code Online (Sandbox Code Playgroud)
source_file.cpp:15:10: 错误:对成员函数“set”的调用不明确 dict.set(0);
source_file.cpp:8:10: 注意:候选函数
Run Code Online (Sandbox Code Playgroud)void set(const char *Str) { std::cout << "1"; }source_file.cpp:9:10: 注意:候选函数
Run Code Online (Sandbox Code Playgroud)void set(int64_t val) { std::cout << "2"; }
那么这里发生了什么 - 哪个编译器是正确的?如果 GCC 和 Clang 都接受不正确的代码,或者 MSVC 只是有问题,我会感到惊讶吗?请参考标准
在 C++11 及之前,任何计算结果为 0 的整型常量表达式都被视为空指针常量。这在 C++14 中受到限制:仅考虑值为 0 的整数文字。此外,std::nullptr_t自 C++11 起,类型的纯右值是空指针常量。参见 [conv.ptr] 和CWG 903。
关于重载解析,积分转换unsigned->int64_t和指针转换空指针常量->const char*都具有相同的等级:转换。参见 [over.ics.scs] / 表 12。
所以如果ProtocolMinorVersion被认为是一个空指针常量,那么调用是不明确的。如果你只是编译下面的程序:
static const unsigned ProtocolMinorVersion = 0;
int main() {
const char* p = ProtocolMinorVersion;
}
Run Code Online (Sandbox Code Playgroud)
您将看到 clang 和 gcc 拒绝这种转换,而 MSVC 接受它。
由于 CWG 903 被认为是一个缺陷,我认为 clang 和 gcc 是正确的。