在下面的程序中,应该选择哪个(如果有的话)转换函数,以及为什么?
int r;
struct B {};
struct D : B {};
struct S {
D d;
operator D&(){r=1; return d;} // #1
operator B&(){r=2; return d;} // #2
};
int main() {
S s;
B& b = s;
return r;
}
gcc和clang都选择了转换函数#2,但是为什么呢?
标准他说
(1)在dcl.init.ref中指定的条件下,引用可以直接绑定到将转换函数应用于初始化表达式的结果。重载解析用于选择要调用的转换函数。假设“对cv1 T的引用”是被初始化的引用的类型,而“cv1”是初始化表达式的类型,对于S是一个类类型,则选择候选函数如下: (1.1) -考虑S及其基类的转换函数。那些不隐藏在S中的非显式转换函数和屈服类型“cv2 T2的lvalue引用”(当初始化lvalue引用或对函数的rvalue引用时)或“cv2 T2”或“对cv2 T2的rvalue引用”(当初始化rvalue引用或对函数的lvalue引用时),其中“cv1 T”是与“cv2 T2”兼容的引用。对于直接初始化,那些未隐藏在S中的显式转换函数和屈服类型“lvalue引用到cv2 T2”(初始化lvalue引用或对函数的rvalue引用时)或“cv2 T2的rvalue引用”(当初始化rvalue引用或对函数的lvalue引用时),其中T2是与T相同的类型,或者可以通过限定转换转换为T类型,也是候选函数。 (2)参数列表有一个参数,即初始值表达式。 注意:这个参数将与转换函数的隐式对象参数进行比较。- end注意事项
这里我们有两个候选函数#1和#2,它们都是可行的--如果其中一个被删除,程序仍然会编译。这两个转换函数只使用隐式参数,并对其具有相同的cv-和ref-限定。因此,没有一个应该是最可行的,程序也不应该编译。它为什么要编译?
发布于 2019-06-11 15:03:17
如您所知,过载分解分三个阶段进行:(1)枚举候选函数;(2)确定哪些候选函数是可行的;(3)选择最佳可行函数。
根据Over.Match.最好的/1:
..。一个可行的函数
F1
被定义为比另一个可行函数F2
更好的函数,如果对于所有参数i,ICSi(F1
)不是比ICSi(F1
)更差的转换序列,那么
F1
)是比ICSj(F2
)更好的转换序列,或者,如果不是这样,F1
的返回类型到目标类型的标准转换序列(即正在初始化的实体的类型)比从F2
返回类型到目标类型示例的标准转换序列要好.或者,如果不是那样,从s
到#1或#2的隐式对象参数所需的隐式转换是身份转换,因此ICS1(#1)和ICS2(#1)是不可区分的,第二个要点在这里是相关的。在#1的情况下,需要从转换函数的返回类型(即D&
)转换为所需的类型,即B&
。对于#2,标准转换序列是身份转换(B&
到B&
),这更好。因此,在这种情况下,选择函数#2比#1更好。
https://stackoverflow.com/questions/56546047
复制相似问题