提问人:H Bellamy 提问时间:2/27/2017 最后编辑:H Bellamy 更新时间:2/27/2017 访问量:523
MSVC 发现此方法调用模棱两可,而 Clang/GCC 则不然,这是否正确?
Is MSVC right to find this method call ambiguous, whilst Clang/GCC don't?
问:
运行此代码时,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): note: or '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);
}
我认为 MSVC 是对的 - 的值是 ,可以是 或 。ProtocolMajorVersion
0
NULL
int64_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"; }
source_file.cpp:9:10:注意:候选函数
void set(int64_t val) { std::cout << "2"; }
那么这是怎么回事 - 哪个编译器是正确的?如果 GCC 和 Clang 都接受不正确的代码,或者 MSVC 只是有问题,我会感到惊讶吗?请参考标准
答:
当两个编译器同意而一个编译器不同意时,几乎总是那个不这样做的编译器是错误的。
我认为,如果你将一个值声明为 ,它不再是一个简单的零,它是一个值为零的命名无符号常量。因此,不应被视为等同于指针类型,只留下一个合理的候选者。const unsigned somename = 0;
话虽如此,这两个函数都需要转换(它不是 a ,也不是 a),所以有人可能会争辩说 MSVC 是对的 [编译器应选择需要最少转换的类型,如果多个类型需要相等量的转换,则它是模棱两可的] - 尽管我仍然认为编译器不应该接受值为零的命名常量作为指针的等价物......set
uint64_t
const char *
对不起,可能更多的是“评论”而不是答案——我开始写这篇文章的目的是说“gcc/clang 是对的”,但后来想了想,得出的结论是“虽然我会对这种行为更满意,但不清楚这是正确的行为”。
评论
int
long long
0
char*
在 C++11 及更早版本中,任何计算结果为 0 的整数常量表达式都被视为空指针常量。这在 C++14 中受到限制:只考虑值为 0 的整数文本。此外,类型的 pr值是自 C++11 以来的空指针常量。参见 [conv.ptr] 和 CWG 903。std::nullptr_t
关于重载分辨率,整数转换 -> 和指针转换空指针常量 -> 具有相同的秩:Conversion。参见 [over.ics.scs] / 表 12。unsigned
int64_t
const char*
因此,如果被视为空指针常量,则调用是不明确的。如果您只编译以下程序:ProtocolMinorVersion
static const unsigned ProtocolMinorVersion = 0;
int main() {
const char* p = ProtocolMinorVersion;
}
您将看到 clang 和 gcc 拒绝此转换,而 MSVC 接受它。
由于 CWG 903 被认为是一个缺陷,我认为 clang 和 gcc 是对的。
评论
struct S { int x; }
S().x
评论