在课堂内,为什么`auto b() - > decltype(a()){}`有效,但是`decltype(a())b(){}`不行吗?

时间:2016-05-04 22:01:14

标签: c++ language-lawyer

请考虑以下代码:(Ideone)

struct S
{
    int a() {return 0;}
    decltype(a()) b() {return 1;}
};

它给了我以下错误:

  

错误:无法调用成员函数' int S :: a()'没有对象


另一方面,此代码编译良好:(Ideone)

struct S
{
    int a() {return 0;}
    auto b() -> decltype(a()) {return 1;}
};


为什么一个例子有效,但另一个例子无法编译?

两个示例中的编译器行为是否完全正确?

如果编译器是正确的,那么为什么标准要求这种奇怪的行为?

2 个答案:

答案 0 :(得分:18)

由于a是非静态成员函数,a()被解释为(*this).a()。引用部分来自[expr.prim.general] / 3,

  

如果声明声明了类X的成员函数或成员函数模板,则表达式this   是可选 cv-qualifer-seq 和结尾之间的“指向 cv-qualifier-seq X的指针”的prvalue    function-definition member-declarator 声明符。它不会出现在可选的 cv-qualifier-seq 之前   它不应出现在静态成员函数的声明中(尽管它的类型和值   category在静态成员函数中定义,因为它们在非静态成员函数中。)

trailing-return-type 位于可选的 cv-qualifier-seq 之后(在您的示例中省略,因为S::b不是cv限定的)所以this可以出现在那里,但之前不会出现。

答案 1 :(得分:10)

@Brian's answer的一些补充:

  1. 在第一个示例中,a() 转换为(*this).a()。该转换在[class.mfct.non-static]/3中指定,并且仅在可以使用this的情况下发生#34;"。如果没有这种转换,代码就会因为违反[expr.prim.id]/2

    而形成错误
      

    id-expression ,表示非静态数据成员或非静态数据成员   只能使用类的成员函数:

         
        
    • 作为类成员访问([expr.ref])的一部分,其中对象表达式引用成员的类 63 或类   派生自该类,或

    •   
    • 形成指向成员的指针([expr.unary.op])或

    •   
    • 如果 id-expression 表示非静态数据成员,并且它出现在未评估的操作数中。

    •   

    使用 id-expression a,表示非静态成员函数,在允许的上下文之外。

  2. 转换为类成员访问权限的事实并不重要,因为它使以下代码有效:

    struct A {
        int a;
        decltype(a) b();
    };
    

    如果上面的decltype(a)转换为decltype((*this).a),那么代码就会格式不正确。

  3. *this特别豁免通常规则,即类成员访问中的对象必须具有完整类型([expr.prim.this]/2):

      

    与其他上下文中的对象表达式不同,*this不需要为成员函数体外的类成员访问([expr.ref])的完整类型。