初始化const左值引用时,返回右值的转换函数是否会被考量?
struct A { }; struct B{ operator A() {}; }; int main(){ B b; const A& a = b; // OK }
条款适用判断疑问
引用初始化规则参考[dcl.init.ref]/5:
类型为“
cv1 T1”的引用由类型为“cv2 T2”的表达式初始化时,规则如下:
- (5.3) 否则,若初始化表达式
- (5.3.1) [省略]
- (5.3.2) 拥有类类型(即
T2为类类型),且T1与T2无引用关联关系,同时可转换为类型“cv3 T3”的右值或函数左值,其中“cv1 T1”与“cv3 T3”引用兼容(参见[over.match.ref])
我认为此处适用(5.3.2)条款:初始化表达式为类类型B,A与B无引用关联关系,这个判断是否正确?
我理解cv3 T3是转换函数B::operator A的返回类型A。因此初始化表达式b可通过B::operator A转换为A类型的右值,且const A(即cv1 T1)与A(即cv3 T3)引用兼容。假设此判断正确,继续分析:
转换函数候选资格疑问
再看[over.match.ref]条款:
在[dcl.init.ref]规定的条件下,引用可直接绑定到对初始化表达式应用转换函数后的结果。通过重载决议选择要调用的转换函数。假设待初始化的引用类型为“
cv1 T引用”,初始化表达式类型为“cv S”(S为类类型),候选函数的选择规则如下:
- (1.1) — 考虑
S及其基类的转换函数。那些未在S中隐藏、且返回类型为“cv2 T2左值引用”(初始化左值引用或函数右值引用时),或“cv2 T2”、“cv2 T2右值引用”(初始化右值引用或函数左值引用时)的非显式转换函数,且“cv1 T”与“cv2 T2”引用兼容,则这些函数为候选函数
我正在初始化左值引用,所以似乎只有返回左值引用的转换函数会被纳入考量。但转换函数B::operator A返回的是右值,并非左值。这意味着什么?B::operator A是否属于候选函数?我是否误解了条款措辞?
解答
条款适用判断正确
你对[dcl.init.ref]/5.3.2的适用判断完全正确。A与B既非同一类型也无继承关系(无引用关联),初始化表达式b是类类型B,且可通过转换函数生成A类型右值,const A与A属于引用兼容类型,完全满足该条款的触发条件。转换函数属于候选函数,你误解了条款的场景区分
[over.match.ref]的条款措辞需要结合引用的const限定来理解:- 当初始化的是非const左值引用时,确实仅允许返回左值引用的转换函数作为候选,因为非const左值引用不能绑定到临时对象;
- 但当初始化的是const左值引用时,标准允许其绑定到临时对象,因此返回值类型(即
cv2 T2,你的代码中就是A)的转换函数同样符合候选条件。
你的代码中初始化的是
const A&,B::operator A()返回A值类型,属于条款中“cv2 T2”的范畴,且const A与A引用兼容,因此该转换函数是合法的候选函数。重载决议选中它后,会生成一个临时A对象,const A&会绑定到这个临时对象上,这也是代码能够正常编译的原因。
内容的提问来源于stack exchange,提问作者mada

