phi*_*uru 4 c++ syntax type-conversion
表达式x->y需要x是指向完整类类型的指针,或者何时x是类的实例,需要operator->()定义x.但是当后者是这种情况时,为什么不能使用转换函数(x即将对象转换为指针)?例如:
struct A
{
int mi;
operator A*() { return this; }
};
int main()
{
A a;
a[1]; // ok: equivalent to *(a.operator A*() + 1);
a->mi; // ERROR
}
Run Code Online (Sandbox Code Playgroud)
这会给出一条错误消息:
error: base operand of '->' has non-pointer type 'A'
但问题是,为什么不使用它a.operator A*(),就像它一样a[1]?
这是由于表达式中运算符的特殊重载解析规则.对于大多数运算符,如果任一操作数具有类或枚举类型,则运算符函数和内置运算符相互竞争,并且重载决策确定将使用哪个操作符.这就是发生的事情a[1].但是,有一些例外情况,适用于您案件的例外情况见标准中的第[13.3.1.2p3.3]段(所有引文中的重点是:
(3.3) - 对于运算符
,,一元运算符&或运算符->, 内置候选集是空的.对于所有其他运算符,内置候选项包括13.6中定义的所有候选运算符函数,与给定运算符相比,
- 具有相同的运营商名称,和
- 接受相同数量的操作数,和
- 接受根据13.3.3.1可以转换给定操作数或操作数的操作数类型,和
- 没有与非函数模板特化的非成员候选者相同的参数类型列表.
因此,对于a[1],用户定义的转换用于获取[]可以应用内置运算符的指针,但是对于那里的三个例外,仅首先考虑运算符函数(在这种情况下没有任何函数) ).后来,[13.3.1.2p9]:
如果操作员是操作员
,,一元操作员&或操作员->,并且没有可行的功能,则假定操作员是内置操作员并根据第5章解释.
简而言之,对于这三个运算符,仅当其他所有操作都失败时才会考虑内置版本,然后他们必须在没有任何用户定义的转换的情况下处理操作数.
据我所知,这是为了避免混淆或模棱两可的行为.例如,内置运营商,和&将是可行的(几乎)所有操作数,所以超载,如果他们将在重载的正常步骤中认为他们是行不通的.
运算符->在重载时具有异常行为,因为它可能导致一系列过载调用->,如[注释129]中所述:
如果函数返回的值
operator->具有类类型,则可能导致选择并调用另一个operator->函数.重复该过程,直到operator->函数返回非类类型的值.
我想你有可能从一个重载的类开始->,它返回另一个类类型的对象,它不会重载->但是有一个用户定义的转换为指针类型,导致最终调用in ->被认为有点混乱.将此限制为显式重载->看起来更安全.
所有引用均来自当前工作草案N4431,但相关部分自C++ 11以来没有改变.