C++ 运算符[](常量字符*)歧义
下面的代码C++ 运算符[](常量字符*)歧义,c++,C++,下面的代码 #include <string> struct Foo { operator double() { return 1; } int operator[](std::string x) { return 1; } }; int main() { Foo()["abcd"]; } #包括 结构Foo{ 运算符双(){ 返回1; } int运算符[](标准::字符串x){ 返回1; } }; in
#include <string>
struct Foo {
operator double() {
return 1;
}
int operator[](std::string x) {
return 1;
}
};
int main() {
Foo()["abcd"];
}
#包括
结构Foo{
运算符双(){
返回1;
}
int运算符[](标准::字符串x){
返回1;
}
};
int main(){
Foo()[“abcd”];
}
使用g++可以很好地编译,但使用clang和intel编译器会失败,因为声明的方法与本机运算符[]
之间存在歧义
我很清楚,如果
Foo
有一个到int
的隐式转换,但是这里的转换是到double
。这难道不能解决歧义吗?§13.3.3.1.2[超过ics.user]/p1-2:
用户定义的转换序列由初始标准组成
用户定义转换后的转换顺序(12.3)
然后是第二个标准转换序列。如果用户定义了
转换由构造函数(12.3.1)指定,初始
标准转换序列将源类型转换为
构造函数的参数所需。如果用户定义了
转换由转换函数(12.3.2)指定,初始
标准转换序列将源类型转换为隐式类型
转换函数的对象参数
第二个标准转换序列转换
用户定义的到序列目标类型的转换
特别是,存在从浮点到整数类型的隐式转换(§4.9[conv.fpint]/p1):
浮点类型的prvalue可以转换为
整数类型。转换截断;即小数部分
被丢弃。如果无法定义截断的值,则行为未定义
无法在目标类型中表示
为了解决过载问题,适用的候选方案包括:
Foo::operator[](std::string x) // overload
operator[](std::ptrdiff_t, const char *); // built-in
给定类型的参数列表(Foo,const char[5])
为了匹配第一个运算符函数,第一个参数是完全匹配的;第二个需要用户定义的转换
为了匹配第二个内置函数,第一个参数需要用户定义的转换序列(用户定义的到double
的转换,然后是到std::ptrdiff_t
的标准转换,一种浮点积分转换)。第二个参数需要标准的数组到指针的转换(仍然是精确的匹配秩),这比用户定义的转换要好
因此,对于第一个参数,第一个函数更好;对于第二个参数,第二个函数更好,我们有一个交叉的情况,重载解析失败,并且程序是病态的
请注意,尽管出于运算符重载解析的目的,用户定义的转换序列可以有两个标准转换序列(一个在用户定义转换之前,一个在用户定义转换之后),如果选择了内置运算符,则可以转换非类类型的操作数以匹配候选操作数,第二个标准转换序列不适用于类类型的操作数,在将运算符解释为内置运算符之前,也不适用于非类类型的操作数(§13.3.1.2[over.match.oper]/p7):
如果通过重载解析选择了内置候选项,则
类类型的操作数转换为相应
所选操作功能的参数,但第二个
用户定义的转换序列的标准转换序列
(13.3.3.1.2)不适用。然后将运算符视为
相应的内置运算符,并根据第5条进行解释
因此,如果删除了
Foo::operator[](std::string x)
,编译器应该报告一个错误,尽管clang没有。这是一个明显的铿锵错误,因为。如果将转换运算符删除为double
,会发生什么情况?在没有转换运算符的情况下,我可以在铿锵上正常工作。这与在我的计算机上删除Foo::operator[]
?@n.m.使用icl(icc的Windows版本)时使用icc编译的问题几乎相同,它确实可以编译。但是icl也错误地编译了§13.3.1.2[over.match.oper]/p7中标准规定不应该编译的一个例子,所以……但是clang拒绝将1.0[“foo”]
视为无效。@n.m.这也是正确的-在这种情况下没有重载解决方案。此外,如果重载解析选择了内置的,结果就不一定有效。在我的机器上,clang抱怨Foo::operator[](std::string)
和内置的operator[](int,const char*)
(不涉及ptrdiff)之间存在歧义。当您删除Foo::operator[]
时,它会愉快地选择一个没有错误的内置函数。但内置函数要求其中一个参数为整型。你怎么解释呢?@n.m.std::ptrdiff\u t
是一个有符号整数类型的typedef(显然在你的机器上是int
——我假设它是32位?)。第二个是叮当作响的虫子。它不应该转换非类类型的参数,也不应该为类类型的参数应用第二个标准转换序列,但它确实转换了。(1) 内置元素不可行,因此应从重载集中删除它,并选择Foo::operator[]
作为唯一剩余的元素。因为clang错误地认为内置是可行的,所以这种情况不会发生。(2) 该标准意味着内置是可行的,并要求在过载解决阶段后将其拒绝。如果是这种情况,那就是标准中的缺陷(一种意外的、不合逻辑的行为,没有任何理由)。