【问题标题】:Why is the enclosing type of a static lambda member incomplete?为什么静态 lambda 成员的封闭类型不完整?
【发布时间】:2018-03-15 00:22:34
【问题描述】:

我今天尝试做类似的事情。我很惊讶它没有编译。

struct Test {
//  v----- Remove me to compile
    //  /*
    static constexpr auto get_test1 = [](Test const& self) {
        return self.test; // error, Test is incomplete
    };
    // */

    // Handwritten version of the lambda
    struct {
        constexpr auto operator() (Test const& self) const {
            return self.test; // ok
        }
    }
    static constexpr get_test2{};

    int test;
};

Live example

它表示Test 类型在范围内不完整。然而 lambda 的手写版本确实有效。这样做的技术原因是什么?是标准中的疏忽,还是有特定的措辞使 Test 在 lambda 中不完整?

【问题讨论】:

  • 自从CWG 1836之后,似乎两者都可以。
  • @xskxzr 不确定是否相关,我什至没有使用尾随返回类型
  • 注意第二个变化,点之前的子表达式不再需要是完整的类类型。

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


【解决方案1】:

这是我能找到的:

§5.1.2 Lambda 表达式 [expr.prim.lambda]

  1. [...] [ 注意:在 lambda 声明符中引用的名称在 lambda 表达式出现的上下文中查找。 ——尾注]

  2. lambda 表达式的复合语句产生函数调用运算符的函数体 (8.4),但用于名称查找 (3.4), [...] 复合语句是在上下文中考虑的 lambda 表达式。

如果我没有误读标准,这意味着参数和正文中的 Testself 都在 lambda 的上下文中进行查看/考虑,这是 Test 所在的类范围不完整。

至于为什么允许嵌套类:

§9.2 类成员 [class.mem]

  1. 在 classspecifier 的结束 } 处,类被视为完全定义的对象类型 (3.9)(或完整类型)。内 类成员规范,类被认为是完整的 函数体、默认参数、使用声明 继承构造函数 (12.9)、异常规范和 用于非静态数据成员(包括 嵌套类中的此类内容)。否则视为不完整 在它自己的类成员规范中。

【讨论】:

  • @xskxzr 再读一遍:“非静态数据成员的大括号或等号初始化器”
【解决方案2】:

我认为你的编译器是正确的。 Test 仍然不完整。此类数据成员的初始化程序(要求类型完整)的处理不会延迟到类定义结束。

我找不到处理此问题的标准部分,但我记得它是作为 C++17 草案(US 24,P0488R0)的国家机构评论提出的:

当前规范禁止constexpr static 数据成员与 封闭类。

例子:

struct A {
   int val;
   static constexpr A cst = { 42 };  // error
}; 

显然,完全取消限制可能会导致一些重大变化,因此评论“没有增加共识”。

【讨论】:

  • get_test1 与封闭类的类型不同
  • @LightnessRacesinOrbit 我知道。但是封闭类用于初始化。据我了解,情况是一样的。
  • @metalfox no 封闭类不用于初始化。我有一个与封闭类相同的函数参数。
  • @GuillaumeRacicot 您正在以需要 Test 完成的方式初始化闭包对象 get_test1,我认为它还没有到那个时候。
  • @metalfox 我很难理解get_test1get_test2 的不同之处。两者都是闭包对象,都需要Test才能完成,但语法很好的那个失败了。
猜你喜欢
  • 1970-01-01
  • 2015-08-09
  • 2014-02-04
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 2012-07-28
  • 1970-01-01
相关资源
最近更新 更多