C++ 给定以下代码(在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)无法在两者之间进行选择 (可能是最符合标准

给定以下代码(在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)无法在两者之间进行选择

(可能是最符合标准的编译器)出现以下错误:

"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的返回类型设置为目标类型
在13.3.3.2中:

13.3.3.2隐式转换序列排名[超过ics排名] 3-两个相同形式的隐式转换序列是不可区分的转换序列,除非其中一个 下列规则适用:[……]

  • 如果用户定义的转换序列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没有查看编译器的源代码,我推测他们错误地将身份转换排序在左值到右值转换之上。这似乎是一个普遍的问题;请参阅编译器错误地将身份转换列为资格转换之上的一个实例。如果您能从您引用的段落中给出相关引用并解释发生了什么,那就太好了。转换对我来说是个谜。