是否在格式正确的另一个成员函数的尾随返回类型中获取了推导成员函数的decltype?

时间:2019-02-20 21:06:06

标签: c++ language-lawyer

无论是谁说这个问题是问题“ Is there a specific reason why a trailing-return-type is not a complete-class context of a class?”的重复,都不知道他/她在说什么。尾随返回类型不是类的完整类上下文这一事实说明了为何此问题中的代码无法编译,尽管它说明了答案中给出的代码被拒绝另一个问题,特别是涉及成员函数quxbaz的部分代码,如OP所述。

为了阐明我的论点,以下代码是有效的,您必须考虑[expr.prim.this]中的the second note,它表示:在尾随返回类型中,出于类成员访问的目的,不需要完全定义所定义的类。稍后声明的类成员是不可见的。由于在我的示例中foo是在bar之前声明的,因此没有什么可以阻止编译器在尾随返回中访问foo的情况, bar的类型。

请注意,@ NathanOliver的the comment below基于这样的猜想,即下面的成员函数foo的内联定义只是语法糖。这需要从标准中的引用中得到证明。 我还没有发现。一旦产生了报价,我肯定会接受一个答案,认为该代码无法编译,因为尾随返回类型不是类的完整类上下文。

struct Test {
        auto foo() {}                       
        auto bar() -> decltype(foo()) {}
    };

prog.cc:3:32: error: use of 'auto Test::foo()' before deduction of 'auto'
    3 |     auto bar() -> decltype(foo()) {}
      |                                ^
prog.cc:3:32: error: use of 'auto Test::foo()' before deduction of 'auto'

[dcl.spec.auto]/9

  

如果具有声明的返回类型的函数使用占位符类型   没有不丢弃的返回语句,返回类型推导为   虽然从return语句的结束括号中没有操作数   功能主体。 [示例:

     

auto f() { } // OK, return type is void

     

auto* g() { } // error, cannot deduce auto* from void()

     

-示例]

[dcl.type.auto.deduct]/(2.1)

  

包含占位符类型的类型T和对应的   初始化程序e的确定如下:

     

(2.1)表示不丢弃   在用返回类型声明的函数中出现的return语句   包含占位符类型,T是声明的返回类型,e   是return语句的操作数。 如果return语句没有   操作数,那么evoid() ;

     

(2.2)对于用a声明的变量   包含占位符类型的类型,T是声明的类型   变量,e是初始化程序。如果初始化是   直接列表初始化,初始化器应为   仅包含一个赋值表达式和e的braced-init-list   是赋值表达式;

     

(2.3)用于非类型模板   使用包含占位符类型的类型声明的参数,T为   非类型模板参数的声明类型,e是   相应的模板参数。

根据[dcl.spec.auto] / 9和[dcl.type.auto.deduct] /(2.1),应编译代码。但是GCC和克兰拒绝了它。我想念什么?

1 个答案:

答案 0 :(得分:4)

struct Test
{
    auto foo() { /*1*/ }                       
    auto bar() -> decltype(foo()) {}
};

在标记1处,名称Test::barstruct Test的所有其他成员一起在范围内。因此,编译器无法在类完成之前分析foo()的正文。

然后我们进行部分排序:

  • 在推断Test::foo()的返回类型之前先对其进行解析
  • 在解析Test的正文之前,完成类Test::foo()
  • 在完成课程Test::bar()之前分析Test的尾随返回类型(根据您提出的问题不是欺骗)

并通过传递性,必须对Test::bar()的返回类型进行分析,而无需对Test::foo()进行返回类型推导。


由于请求了标准报价,因此它来自[class.mem]

  

class-specifier 的结尾}处,类被视为完全定义的对象类型(或完整类型)。在类成员规范中,该类在函数体内被视为完整的,默认参数, noexcept-specifiers 和默认成员初始化程序(包括嵌套类中的此类内容)。否则,在其自己的类成员规范中,它被认为是不完整的。