为什么这个引用绑定不合格?

考虑以下代码:为什么这个引用绑定不合格?

int **p = 0; 

class S {

public:

explicit operator int**&() {

return p;

}

};

int main() {

S a;

int *const*&b (a); // error in both g++-7 and clang-5.0 with "-std=c++17"

return 0;

}

你们会同意

  • int**资格转换为int*const*是可能的,
  • int *const*&b (a)直接初始化

首先,我们参考来自n4700的11.6.3段落[dcl.init.ref]。

的参考输入“CV1T1 (= int*const*)”是由一种类型的表达式初始化“CV2T2 (= S)”如下:

  • 如果参考是一个左值参考和初始化表达式

    • ...
    • 具有类类型(即,T2是一个类型),其中T1不引用相关于T2,并且可以被转换成类型的左值“CV3T3”,其中“CV1T1”是参考兼容“CV3T3”(这种转换通过枚举适用转换函数(16.3.1.6)和通过重载解析(16.3)选择最好的一个所选择的),

然后的引用绑定到在第一种情况下的初始化表达式左值和到在第二种情况下转换的左值结果...

这里,我们预计T3int*const*。如上所述,是否可能转换是根据16.3.1.6第1段[over.match.ref]确定的。

...假设“参照CV1T”是基准是 初始化的类型,和“CVS”是初始值设定表达式的类型,与S类类型,候选功能选择如下:

  • ...对于直接初始化,那些显式转换函数该 没有内S和产量类型隐藏的“左值参考CV2T2”或“CV2T2”或“右值参照CV2T2”,分别其中T2T相同,或者可以转换为T类型,并且资格转换也是候选功能。

这里,S::operator int**&产量“左值参照T2 (= int**)”,它可以通过一个资格转换被转换为T (= int*const*)。在这里,我们可以说转换是可能的,但是程序在g ++ - 7和clang-5.0中都不被接受。这是为什么?

回答:

我们正在寻找的参考初始化规则是[dcl.init.ref]:

的参考输入“CV1T1”是由一种类型的表达式“CV2T2”初始化如下:

我们有cv1T1 as int* const* and cv2T2 as S。然后,我们经过仔细下一节:

如果引用是一个左值引用和初始化表达式

  • 是一个左值(但不是位域),以及“CV1 T1”是参考兼容“CV2 T2”,或
  • 具有类类型(即,T2是一个类型),其中,T1是不能引用相关于T2,并且可以被转换为左值类型的“ cv3 T3“,其中”cv1 T1“与”cv3 T3“参考兼容(this转换是通过枚举适用转换功能中选择([over.match.ref])和选择最佳的一个通过载分辨率),

那么参考结合到初始化表达式左值在第一种情况下,并在第二种情况下(或者在任何情况下)转换为对象的适当基类子对象的左值结果。

我们的参考是一个左值参考。初始化表达式是一个左值,但这两种类型不是reference-compatible,所以第一个项目符号不适用。

初始值设定项表达式具有非参考相关的类类型,但不能转换为参考兼容类型。参考兼容部分很重要。 int**是不是参考兼容int* const*,而前者可以转换为后者,结果不会是一个左值 - 这也是必需的。

所以,本节不适用,我们move on。

否则,引用应该是对非易失性常量类型的左值引用(即cv1应该是const),或者引用应该是右值引用。

我们的参考资料不符合这些标准,因此初始化不合格。


这种失败的一个简化版本是:

int* pi; 

int const*& r = pi; // error

我们无法通过资格转换去的时候,我们有一个左参考非const类型。

以上是 为什么这个引用绑定不合格? 的全部内容, 来源链接: utcz.com/qa/265776.html

回到顶部