鉴于以下代码(在GCC 4.3中),为什么在这两种情况下都会调用转换为引用?
class A { };
class B {
public:
operator A() {}
operator A&() {}
};
int main() {
B b;
(A) b;
(A&) b;
}
Run Code Online (Sandbox Code Playgroud)
您的代码是不明确的,不应该编译(这是病态的每13.3.3:2).
左值到右值的转换与身份转换具有相同的等级,因此(按照13.3.3:1),无法在它们之间进行选择.
Comeau C++(可能是最符合标准的编译器)给出以下错误:
"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;
^
Run Code Online (Sandbox Code Playgroud)
以下是标准中的相关文字:
13.3.3最佳可行功能[over.match.best]
[...]鉴于这些定义,一个可行的函数F1被定义为比另一个可行的函数F2更好的函数[...]
2 - 如果只有一个可行的函数比所有其他可行函数更好的函数,则它是通过重载决策选择的函数; 否则电话会形成不良.
定义本身很复杂,但用户定义的转换有两点需要注意:
首先,指定将用户定义的转换应用为转换序列,以分解为S_a - U - S_b标准转换序列的序列,然后是用户定义的转换,然后是另一个标准转换序列.这包括所有案件; 转换序列中不能有多个用户定义的转换,标准转换序列可以是"标识转换",即不需要转换.
其次,在比较用户定义的转换序列时,唯一重要的部分是第二个标准转换序列.这是在13.3.3中:
13.3.3最佳可行功能[over.match.best]
[...]一个可行的功能F1被定义为比另一个可行的功能F2更好的功能,如果[...]
- 上下文是用户定义转换的初始化(见8.5,13.3.1.5和13.3.1.6),从返回类型F1到目标类型的标准转换序列(即,被初始化的实体的类型)是比从返回类型F2到目标类型的标准转换序列更好的转换序列.
在13.3.3.2中:
13.3.3.2对隐式转换序列进行排序[over.ics.rank]
3 - 相同形式的两个隐式转换序列是无法区分的转换序列,除非以下规则之一适用:[...]
- 用户定义的转换序列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]
Run Code Online (Sandbox Code Playgroud)
现在,我们如何对标准转换序列进行排名?要查看的地方是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);
Run Code Online (Sandbox Code Playgroud)
13.3.3适用并被A::operator int()选中A::operator float(); 在代码中
struct A {
operator int();
} a;
void f(int);
void f(double);
f(a);
Run Code Online (Sandbox Code Playgroud)
13.3.3.2适用并被void f(int)选中void f(double).但是在代码中
struct A {
operator int();
operator float();
} a;
void f(int);
void f(double);
f(a);
Run Code Online (Sandbox Code Playgroud)
即使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过float -> int,也没有办法的区分int -> int和float -> double转换序列(因为它们不含有相同的用户定义转换运算符也不相同过载f),和所以代码是不正确的.
| 归档时间: |
|
| 查看次数: |
214 次 |
| 最近记录: |