在类的内部,为什么`auto b() - > decltype(a()){}`有效,但``decltype(a())b(){}`不行?

Hol*_*Cat 21 c++ language-lawyer

请考虑以下代码:( Ideone)

struct S
{
    int a() {return 0;}
    decltype(a()) b() {return 1;}
};
Run Code Online (Sandbox Code Playgroud)

它给了我以下错误:

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


另一方面,这段代码很好编译:( Ideone)

struct S
{
    int a() {return 0;}
    auto b() -> decltype(a()) {return 1;}
};
Run Code Online (Sandbox Code Playgroud)


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

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

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

Bri*_*ian 18

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

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

尾随收益型配备可选的后CV-预选赛-SEQ(在你的例子省略,因为S::b不是CV-合格),这样this就可能会出现,但不能出庭.

  • ......这是因为在你看到cv-qualifier-seq之前你不知道`this`的类型. (10认同)

T.C*_*.C. 10

@Brian答案的一些补充:

  1. 在第一个例子中,a()转化成(*this).a().该转换在[class.mfct.non-static]/3中指定,并且仅在" this可以使用的上下文中"发生.如果没有这种转换,代码就会因为违反[expr.prim.id]/2而形成错误:

    只能使用表示非静态数据成员或类的非静态成员函数的id表达式:

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

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

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

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

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

    struct A {
        int a;
        decltype(a) b();
    };
    
    Run Code Online (Sandbox Code Playgroud)

    如果将decltype(a)上述内容转换为decltype((*this).a),那么代码就会形成错误.

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

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