C++ 给定以下代码(在GCC4.3中),为什么要调用两次到引用的转换?
给定以下代码(在GCC4.3中),为什么在这两种情况下都要调用到引用的转换C++ 给定以下代码(在GCC4.3中),为什么要调用两次到引用的转换?,c++,c++11,C++,C++11,给定以下代码(在GCC4.3中),为什么在这两种情况下都要调用到引用的转换 class A { }; class B { public: operator A() {} operator A&() {} }; int main() { B b; (A) b; (A&) b; } 您的代码不明确,不应编译(根据13.3.3:2,它的格式不正确) 左值到右值的转换与标识转换具有相同的等级,因此(根据13.3.3:1)无法在两者之间进行选择 (可能是最符合标准
class A { };
class B {
public:
operator A() {}
operator A&() {}
};
int main() {
B b;
(A) b;
(A&) b;
}
您的代码不明确,不应编译(根据13.3.3:2,它的格式不正确) 左值到右值的转换与标识转换具有相同的等级,因此(根据13.3.3:1)无法在两者之间进行选择 (可能是最符合标准的编译器)出现以下错误:
"ComeauTest.c", line 11: error: more than one user-defined conversion from "B" to
"A" applies:
function "B::operator A()"
function "B::operator A &()"
(A) b;
^
以下是标准中的相关文本:
13.3.3最佳可行功能[超过.匹配.最佳]
[…]鉴于这些定义,可行函数F1被定义为比另一个可行函数F2更好的函数[…]
2-
如果只有一个可行函数比所有其他可行函数更好,那么它就是
通过过载分辨率选择一个;否则,调用的格式不正确
定义本身很复杂,但用户定义的转换需要注意两件事:
首先,指定用户定义转换作为转换序列的应用,以分解为标准转换序列的序列S_a-U-S_b
,接着是用户定义转换,接着是另一标准转换序列。这涵盖了所有情况;一个转换序列中不能有多个用户定义的转换,标准转换序列可以是“标识转换”,即不需要转换
其次,在比较用户定义的转换序列时,唯一重要的部分是第二个标准转换序列。第13.3.3节:
13.3.3最佳可行功能[超过.匹配.最佳]
[…]可行函数F1被定义为比另一个可行函数更好的函数
F2如果[…]
- 上下文是用户定义转换的初始化(见8.5、13.3.1.5和13.3.1.6)和 从F1返回类型到目标类型的标准转换顺序(即 实体(正在初始化)是一个比标准转换序列更好的转换序列 将F2的返回类型设置为目标类型
- 如果用户定义的转换序列U1包含相同的用户定义的转换函数或构造函数或聚合,则用户定义的转换序列U1比另一个用户定义的转换序列U2更好 U1的初始化和第二个标准转换顺序优于第二个标准 U2的转换序列
U1=(S1_a-U'1-S1_b)
和U2=(S2_a-U'2-S2_b)
唯一重要的是S1_b
和S2_b
的相对等级;达到用户定义的转换参数所需的标准转换序列并不重要
因此,(A)b
的可能转换序列,需要产生b->A
的转换序列,如下所示:
U1: B -> B [identity], B::operator A() [user-defined], A -> A [identity]
U2: B -> B [identity], B::operator A &() [user-defined], A & -> A [rvalue-to-lvalue]
现在,我们如何对标准转换序列进行排序?要查看的地方是13.3.3.1.1中的表12,其中规定左值到右值的转换与标识转换具有相同的秩(“精确匹配”)。因此,无法区分两个用户定义的转换序列,并且程序格式不正确
边栏 13.3.3和13.3.3.2在用户定义的转换序列排名方面有什么不同 13.3.3允许编译器区分不同的用户定义转换运算符;13.3.3.2允许编译器区分不同的函数,每个函数的参数都需要用户定义的转换 所以,在代码中
struct A {
operator int();
operator float();
} a;
void f(int);
f(a);
struct A {
operator int();
} a;
void f(int);
void f(double);
f(a);
struct A {
operator int();
operator float();
} a;
void f(int);
void f(double);
f(a);
13.3.3适用且在A::operator float()
上选择A::operator int()
;在代码中
struct A {
operator int();
operator float();
} a;
void f(int);
f(a);
struct A {
operator int();
} a;
void f(int);
void f(double);
f(a);
struct A {
operator int();
operator float();
} a;
void f(int);
void f(double);
f(a);
13.3.3.2适用,并且在无效f(双)
上选择无效f(int)
。但是在代码中
struct A {
operator int();
operator float();
} a;
void f(int);
f(a);
struct A {
operator int();
} a;
void f(int);
void f(double);
f(a);
struct A {
operator int();
operator float();
} a;
void f(int);
void f(double);
f(a);
尽管13.3.3更喜欢
A::operator int()->void f(int)
而不是A::operator float()->void f(int)
和float->double
而不是int->double
,13.3.3.2更喜欢int->int
而不是int->double
和float->double
,无法区分int->int
和float->double
转换序列(因为它们既不包含相同的用户定义转换运算符,也不包含相同的f
重载),因此代码格式不正确。如何从该代码中区分调用了哪些转换?您正在调试程序中单步执行吗?您是否启用了优化功能?@MarkB请参阅@MarkB或这一个叮当作响的主干和gcc 4.7.1。如果代码允许,comeau在线前端将失败,并出现您的解释所要求的错误。@YamMarcovic没有查看编译器的源代码,我推测他们错误地将身份转换排序在左值到右值转换之上。这似乎是一个普遍的问题;请参阅编译器错误地将身份转换列为资格转换之上的一个实例。如果您能从您引用的段落中给出相关引用并解释发生了什么,那就太好了。转换对我来说是个谜。