MSVC发现这种方法调用模棱两可,而Clang / GCC则不然吗?
Is MSVC right to find this method call ambiguous, whilst Clang/GCC don't?
Clang (3.9.1) 和 GCC(7,快照)在运行此代码时将"1"、"2"打印到控制台。
但是,MSVC 无法编译此代码:
source_file.cpp(15):错误 C2668:"字典::set":对重载函数的不明确调用
source_file.cpp(9):注意:可能是"无效字典::set(int64_t)">
source_file.cpp(8):注意:或"无效字典::设置(常量字符*)">
source_file.cpp(15):注意:在尝试匹配参数列表"(常量无符号整数)"时
#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"的调用不明确 字典集(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 只是有问题,我会感到惊讶吗?请参考标准
在 C++11 及之前版本中,任何计算结果为 0 的整数常量表达式都被视为空指针常量。这在 C++14 中受到限制:仅考虑值为 0 的整数文本。此外,自 C++11 以来,类型std::nullptr_t
的 prvalues 是空指针常量。参见 [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;
}
您将看到 clang 和 gcc 拒绝此转换,而 MSVC 接受它。
由于CWG 903被认为是一个缺陷,我认为clang和gcc是正确的。
当两个编译器同意而一个不同意时,几乎总是那个不同意
的编译器是错误的。我认为,如果您将一个值声明为const unsigned somename = 0;
,它不再是一个简单的零,它是一个值为零的命名无符号常量。所以不应该认为等同于指针类型,只留下一个合理的候选者。
话虽如此,set
两个函数都需要转换(它不是uint64_t
,也不是const char *
),所以有人可能会争辩说 MSVC 是正确的 [编译器应选择需要最少转换的类型,如果多个类型需要相等的转换量,这是模棱两可的] - 尽管我仍然认为编译器不应该接受值零的命名常量作为等价于指针......
抱歉,可能更像是"评论"而不是答案 - 我开始写作的目的是说"gcc/clang 是对的",但后来更多地思考得出的结论是"虽然我会对这种行为更满意,但不清楚这是正确的行为"。
- 奇怪的结构&GCC&clang(void*返回类型)
- 如何让 GCC/Clang 在保留标识符上出错
- Visual C++: MSVC vs. GCC+CLANG: 处理 lambda 捕获类成员变量,正确的方法是什么?
- GCC/CLang不同意模板模板参数的部分特化
- 在 gcc/clang (C++) 中获取函数范围之外的标签地址
- C++指向成员的指针的类内初始化会使 MSVC 失败(但 GCC/Clang 工作)
- ICC 中的 -O2 搞砸了汇编程序,ICC 中的 -O1 和 GCC / Clang 中的所有优化都很好
- 为什么GCC/Clang甚至在最高优化水平上也不会内联
- 在继承多个空类时,了解GCC/Clang vs MSVC2015之间的不同填充规则
- C++ MSVC/GCC/Clang编译器错误
- 这被认为是有效的C 11还是C 14?还是GCC/Clang弄错了
- GCC/Clang上的模板错误,但在MSVC上没有错误
- 如何求解与GCC/Clang不同的C 功能模板的MSVC处理(无法识别的模板定义)
- 忽略 gcc/clang 的"-Wmissing-braces"警告是否明智?
- GCC/Clang 返回元组时x86_64 C++ ABI 不匹配?
- 为什么根据 C++11 标准,std::seed_seq是不可复制的,为什么 gcc/clang 不符合?
- 我可以用更新的 gcc/clang 定位较旧的 Linux 吗?C++
- gcc/clang:错误:未知类名"异常";你是说'std::exception'
- 模板专业化和DLL:Visual Studio vs. (GCC / Clang)
- 使用GCC/CLANG跟踪代码膨胀的工具