eca*_*mur 3 c++ constructor conversion-operator language-lawyer implicit-conversion
该标准似乎提供了两个规则来区分涉及用户定义的转换运算符的隐式转换序列:
13.3.3最佳可行功能[over.match.best]
[...]一个可行的功能F1被定义为比另一个可行的功能F2更好的功能,如果[...]
- 上下文是用户定义转换的初始化(见8.5,13.3.1.5和13.3.1.6),从返回类型F1到目标类型的标准转换序列(即,被初始化的实体的类型)是比从返回类型F2到目标类型的标准转换序列更好的转换序列.
13.3.3.2对隐式转换序列进行排序[over.ics.rank]
3 - 相同形式的两个隐式转换序列是无法区分的转换序列,除非以下规则之一适用:[...]
- 用户定义的转换序列U1是比另一个用户定义的转换序列U2更好的转换序列,如果它们包含相同的用户定义的转换函数或构造函数或聚合初始化,并且U1的第二标准转换序列优于第二标准转换序列U2.
据我了解,13.3.3允许编译器区分不同的用户定义的转换运算符,而13.3.3.2允许编译器区分不同的函数(某些函数的重载f),每个函数都需要在参数中进行用户定义的转换(请参阅我的侧边栏给出以下代码(在GCC 4.3中),为什么转换为引用调用两次?).
是否有其他规则可以区分用户定义的转换序列?/sf/answers/96883111/上的答案表明,13.3.3.2:3可以根据隐式对象参数(转换运算符)的cv限定来区分用户定义的转换序列,或者构造函数或聚合初始化的单个非默认参数,但我不知道这是如何相关的,因为这需要比较各个用户定义的转换序列的第一个标准转换序列,标准没有似乎提到了.
假设S1优于S2,其中S1是U1的第一个标准转换序列,S2是U2的第一个标准转换序列,那么U1是否优于U2?换句话说,这段代码是否格式良好?
struct A {
operator int();
operator char() const;
} a;
void foo(double);
int main() {
foo(a);
}
Run Code Online (Sandbox Code Playgroud)
g ++(4.5.1),Clang(3.0)和Comeau(4.3.10.1)接受它,更喜欢非const限定A::operator int(),但我希望它被拒绝为含糊不清且因此格式错误.这是标准中的缺陷还是我对它的理解?
这里的技巧是从类类型转换为非类类型实际上并不将任何用户定义的转换排序为隐式转换序列.
struct A {
operator int();
operator char() const;
} a;
void foo(double);
int main() {
foo(a);
}
Run Code Online (Sandbox Code Playgroud)
在表达式中foo(a),foo显然命名一个非重载的非成员函数.该调用需要double使用单个表达式复制初始化(8.5p14)类型的函数参数,该表达式a是类类型的左值A.
由于目标类型double不是cv限定的类类型,而是源类型A ,因此候选函数由第13.3.1.5节定义,带S=A和T=double.仅考虑类A和任何基类中的转换函数A.如果符合以下条件,则转换函数位于候选集中:
A,而且explicit(因为上下文是复制初始化),和double.好的,两个转换函数都有资格,所以候选函数是
A::operator int(); // F1
A::operator char() const; // F2
Run Code Online (Sandbox Code Playgroud)
使用13.3.1p4中的规则,每个函数都将隐式对象参数作为其参数列表中的唯一内容. F1参数列表是"(左值引用A)",F2参数列表是"(左值引用const A)".
接下来我们检查功能是否可行(13.3.2).每个函数在其参数列表中都有一个类型,并且有一个参数.是否有每个参数/参数对的隐式转换序列?当然:
ICS1(F1):将隐式对象参数(类型左值引用A)绑定到表达式a(类型的左值A).ICS1(F2):将隐式对象参数(类型左值引用const A)绑定到表达式a(类型的左值A).由于没有派生到基础的转换,这些引用绑定被认为是身份转换的特殊情况(13.3.3.1.4p1).是的,这两个功能都是可行的.
现在我们必须确定一个隐式转换序列是否优于另一个.这属于13.3.3.2p3中大列表中的第五个子项:两者都是相同类型的引用绑定,除了顶级cv限定符.由于引用的类型ICS1(F2)比引用的类型更符合cv ICS1(F1),ICS1(F1)因此优于ICS1(F2).
因此F1,或者A::operator int(),是最可行的功能.并且没有用户定义的转换(具有由SCS +(转换构造函数或转换函数)+ SCS组成的ICS类型的严格定义)甚至可以进行比较.
现在,如果foo超载,则a需要比较参数的用户定义转换.因此,用户定义的转换(identity + A::operator int()+ intto double)将与其他隐式转换序列进行比较.