运算符[](const char *)的歧义 [英] operator[](const char *) ambiguity

查看:72
本文介绍了运算符[](const char *)的歧义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码

#include <string>

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

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

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

使用g ++可以很好地进行编译,但是对于clang和intel编译器而言却失败,因为声明的方法与本机运算符 [] 之间存在歧义.

Compiles fine with g++ but fails with clang and intel compilers because of an ambiguity between the declared method and native operator [].

对于我来说很清楚,如果 Foo 隐式转换为 int ,但是这里的转换是 double .那不能解决歧义吗?

It would be clear for me if Foo had an implicit conversion to int, but here the conversion is to double. Doesn't that solve the ambiguity?

推荐答案

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

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

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

A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion (12.3) followed by a second standard conversion sequence. If the user-defined conversion is specified by a constructor (12.3.1), the initial standard conversion sequence converts the source type to the type required by the argument of the constructor. If the user-defined conversion is specified by a conversion function (12.3.2), the initial standard conversion sequence converts the source type to the implicit object parameter of the conversion function.

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

The second standard conversion sequence converts the result of the user-defined conversion to the target type for the sequence.

尤其是从浮点到整数类型的隐式转换(第4.9节[conv.fpint]/p1):

In particular, there's an implicit conversion from floating point to integral type (§4.9 [conv.fpint]/p1):

浮点类型的prvalue可以转换为浮点类型的prvalue整数类型.转换被截断;即小数部分被丢弃.如果截断的值不能,则行为未定义以目标类型表示.

A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

出于解决过载的目的,适用的候选对象是:

For overload resolution purposes, the applicable candidates are:

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

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

Given an argument list of types (Foo, const char [5]).

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

To match the first operator function, the first argument is an exact match; the second requires a user-defined conversion.

要匹配第二个内置函数,第一个参数需要用户定义的转换顺序(用户定义的转换为 double ,然后是标准转换为 std :: ptrdiff_t,即浮点整数转换).第二个参数需要一个标准的数组到指针的转换(仍然是精确匹配等级),比用户定义的转换要好.

To match the second built-in function, the first argument requires a user-defined conversion sequence (the user-defined conversion to double followed by a standard conversion to std::ptrdiff_t, a floating-integral conversion). The second argument requires a standard array-to-pointer conversion (still exact match rank), which is better than a user-defined conversion.

因此,对于第一个参数,第一个函数更好;对于第二个参数,第二个函数更好,我们遇到了纵横交错的情况,重载解析失败,并且程序格式错误.

Thus for the first argument the first function is better; for the second argument the second function is better, we have a criss-cross situation, overload resolution fails, and the program is ill-formed.

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

Note that, while for the purposes of operator overload resolution, a user-defined conversion sequence can have two standard conversion sequences (one before and one after the user-defined conversion), and operands of non-class-type can be converted to match the candidates, if a built-in operator is selected, the second standard conversion sequence is not applied for operands of class type, and no conversion at all is applied for operands for non-class type before the operator is interpreted as a built-in (§13.3.1.2 [over.match.oper]/p7):

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

If a built-in candidate is selected by overload resolution, the operands of class type are converted to the types of the corresponding parameters of the selected operation function, except that the second standard conversion sequence of a user-defined conversion sequence (13.3.3.1.2) is not applied. Then the operator is treated as the corresponding built-in operator and interpreted according to Clause 5.

因此,如果删除了 Foo :: operator [](std :: string x),则编译器应报告一个错误,尽管clang不会.这是一个显而易见的clang错误,因为它无法拒绝标准中给出的示例.

Thus if Foo::operator[](std::string x) is removed, the compiler should report an error, though clang doesn't. This is an obvious clang bug, as it fails to reject the example given in the standard.

这篇关于运算符[](const char *)的歧义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆