为什么这个参考绑定格式不正确?

时间:2017-12-27 14:42:26

标签: c++ language-lawyer c++17

考虑以下代码:

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,第5段[dcl.init.ref]。

  

对类型“ cv1 T1 (= int*const*)”的引用由“ cv2 T2 (= S)”类型的表达式初始化,如下所示:

     
      
  • 如果引用是左值引用和初始化表达式      
        
    • ...
    •   
    • 有一个类类型(即,T2是一个类类型),其中T1T2没有引用相关,可以转换到“ cv3 T3”类型的左值,其中“ cv1 T1”与“ cv3 T3“(通过枚举适用的转换函数(16.3.1.6)选择,并通过重载决策选择最佳的转换函数(16.3)),
    •   
  •   
     

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

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

  

...假设“引用 cv1 T”是引用的类型   初始化,“ cv S”是初始化表达式的类型,S是类类型,候选函数选择如下:

     
      
  • ...对于直接初始化,那些显式转换函数   不会隐藏在S和收益类型“左值引用 cv2 T2”或“ cv2 T2”或“右值参考”中分别为 cv2 T2“,其中T2T 的类型相同,或者可以转换为T类型资格转换也是候选函数
  •   

在此处,S::operator int**&会产生"左值T2 (= int**)",并且可以通过资格转换转换为T (= int*const*)在这里,我们可以说转换是可能的,但g ++ - 7和clang-5.0都不接受该程序。那是为什么?

1 个答案:

答案 0 :(得分:7)

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

  

对类型“ cv1 T1”的引用由“ cv2 T2”类型的表达式初始化,如下所示:

我们 cv1 T1int* const* cv2 T2S。然后我们仔细阅读下一节:

  

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

     
      
  • 是左值(但不是位字段),“cv1 T1”与“cv2 T2”引用兼容,或
  •   
  • 有一个类类型(即T2是一个类类型),其中T1与T2无参考相关,可以转换为左值类型为“cv3 T3”,其中“cv1 T1”与“cv3 T3”引用兼容(通过枚举适用的转换函数([over.match.ref])并通过重载分辨率选择最佳转换函数来选择此转换),< / LI>   
     

然后引用绑定到第一种情况下的初始化表达式lvalue和第二种情况下转换的左值结果(或者,在任何一种情况下,绑定到对象的相应基类子对象)。

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

初始化表达式确实具有非引用相关的类类型,但不能将其转换为引用兼容类型。参考兼容部分很重要。 int**与<{1}} 引用兼容,虽然前者可以转换为后者,但结果不是左值 - 这也是必需的。

因此,本节不适用,我们move on

  

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

我们的参考符合这两个标准,因此初始化是不正确的。

这种失败的简单版本是:

int* const*

当我们对非const类型的左值引用时,我们无法进行限定转换。