operator [](const char *)歧义

时间:2014-08-04 07:27:35

标签: c++

以下代码

#include <string>

struct Foo {
    operator double() {
        return 1;
    }

    int operator[](std::string x) {
        return 1;
    }
};

int main() {
    Foo()["abcd"];
}

使用g ++进行编译,但由于声明的方法与本机运算符[]之间存在歧义,因此无法使用clang和intel编译器。

如果Foo隐式转换为int,我会很清楚,但此处转换为double。是不是解决了歧义?

1 个答案:

答案 0 :(得分:7)

§13.3.3.1.2[over.ics.user] / p1-2:

  

用户定义的转换序列由初始标准组成   转换序列后跟用户定义的转换(12.3)   然后是第二个标准转换序列。如果是用户定义的   转换由构造函数(12.3.1)指定,即初始值   标准转换序列将源类型转换为类型   构造函数的参数所需要的。如果是用户定义的   转换由转换函数(12.3.2)指定,即初始值   标准转换序列将源类型转换为隐式   转换函数的对象参数。

     

第二个标准转换序列转换结果   用户定义的转换为序列的目标类型。

特别是,从浮点到整数类型的隐式转换(§4.9[conv.fpint] / p1):

  

浮点类型的prvalue可以转换为a的prvalue   整数类型。转换截断;也就是说,小数部分   被丢弃了。如果截断值不能,则行为未定义   用目的地类型表示。

出于重载决策的目的,适用的候选人是:

Foo::operator[](std::string x)              // overload
operator[](std::ptrdiff_t, const char *);   // built-in

给出类型(Foo, const char [5])的参数列表。

要匹配第一个运算符函数,第一个参数是完全匹配;第二个需要用户定义的转换。

要匹配第二个内置函数,第一个参数需要用户定义的转换序列(用户定义的转换为double,然后标准转换为std::ptrdiff_t,浮点积分转换)。第二个参数需要标准的数组到指针转换(仍然是完全匹配等级),这比用户定义的转换要好。

因此对于第一个参数,第一个函数更好;对于第二个参数,第二个函数更好,我们有一个纵横交错的情况,重载解析失败,程序格式不正确。

注意,虽然为了操作符重载解析的目的,用户定义的转换序列可以有两个标准转换序列(一个在用户定义的转换之前和之后),非类型的操作数可以是转换为匹配候选者,如果选择了内置运算符,则第二个标准转换序列不应用于类类型的操作数,并且在将运算符解释为a类之前,根本不对非类类型的操作数应用转换。内置(§13.3.1.2[over.match.oper] / p7):

  

如果通过重载分辨率选择内置候选,则   类类型的操作数转换为相应的类型   所选操作功能的参数,除了第二个   用户定义的转换序列的标准转换序列   (13.3.3.1.2)不适用。然后操作员被视为   相应的内置运算符,并根据第5条进行解释。

因此,如果删除Foo::operator[](std::string x),编译器应该报告错误,尽管clang没有。这是一个明显的铿锵声,如it fails to reject the example given in the standard