在下面的程序中,应该选择哪个(如果有)转换函数,为什么?
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 select 都选择转换函数#2。但为什么?
标准说:
(1) 在 [dcl.init.ref] 中指定的条件下,引用可以直接绑定到将转换函数应用于初始化表达式的结果。重载分辨率用于选择要调用的转换函数。假设“reference to cv1 T”是被初始化的引用的类型,“cv S”是初始化表达式的类型,其中S是类类型,候选函数选择如下:
(1.1) - 考虑 S 及其基类的转换函数。那些未隐藏在 S 中并产生类型“对 cv2 T2 的左值引用”(初始化对函数的左值引用或右值引用时)或“cv2 T2”或“对 cv2 T2 的右值引用”(当初始化对函数的右值引用或左值引用),其中“cv1 T”与“cv2 T2”引用兼容,是候选函数。对于直接初始化,那些不隐藏在 S 中并产生类型“对 cv2 T2 的左值引用”(当初始化对函数的左值引用或右值引用时)或“对 cv2 T2 的右值引用”(当初始化一个右值引用或函数的左值引用),
(2) 参数列表有一个参数,即初始化表达式。[ 注意:此参数将与转换函数的隐式对象参数进行比较。——尾注]
这里我们有两个候选函数#1 和#2。两者都是可行的——如果其中一个被删除,程序仍然可以编译。两个转换函数都只采用隐式参数,并且具有相同的 cv- 和 ref-qualification。所以没有一个应该是最好的,程序不应该编译。为什么会编译?