【问题标题】:Class type undefined in static member lambda function in C++17C ++ 17中静态成员lambda函数中未定义的类类型
【发布时间】:2019-10-18 15:50:42
【问题描述】:

不久前,我试图实现自己的 v-tables(用于教育目的)。为此,我使用了函数指针和 lambda。在这样做的过程中,我偶然发现了一个问题。我没有发布整个 v-table 代码,而是编写了一个 Minimal Reproducible Example。

由于某种原因,它无法编译(C2027 - 使用未定义类型测试):

class Test
{
    int n;
    static inline auto f = [](Test* t)
    {
        return t->n;
    };
};

即使我像这样转发声明Testclass Test;

我很好奇是什么导致了这种行为,因为 int nclass Test 都是在 lambda 之前声明的。

我正在使用带有 C++17 的最新 Visual Studio 2019。

【问题讨论】:

  • 在定义类之前不能使用它。 t->n; 尝试使用该类。
  • 如果它是内联的并且函数是在类本身中定义的,为什么要使用 lambda?

标签: c++ pointers lambda compiler-errors c++17


【解决方案1】:

Test 在 lambda 之前声明,但未定义。当您执行}; 时,类定义仅在类本身结束时完成。在那之前,它是一个不完整的类型。

而且您不能访问不完整类型的成员。或者至少,不是像在 lambda 中那样通过对象实例(此时您可以谈论 Test::n,但不能接受 Test* 并在其上执行 ->n)。

现在,您可能会说,如果您将f 设为普通静态成员,您可以轻松地将类的定义放在那里并且它会起作用。这是因为 C++ 对类的成员函数的定义有一个特殊的规则。即,这些函数的主体被认为是被定义为就好像它们紧跟在类定义之后一样。因此,他们可以在内部使用该类,就好像它是一个完整类型一样,因为这些函数体将在它们是一个完整类型的地方定义。

您的 lambda 不是成员函数;这是一个分配给类静态变量的 lambda 函数。静态变量的初始化器没有得到这种特殊处理,所以 Test 在 lambda 的函数体内被认为是不完整的。

【讨论】:

  • 感谢您的回答。我能够很容易地修复该功能。我所要做的就是首先存储一个指向成员变量n 的指针。 static inline auto f = [](Test* t) { constexpr static auto nptr = &Test::n; t->*nptr; };
  • @YanB.:或者你可以,你知道的,让它成为一个静态函数。真的没有理由不这样做。
  • 类成员访问is not the problem;就是必须知道 lambda 的类型才能完成类的定义,这违背了用于实现成员函数的延迟解析策略。另请参阅CWG2335
【解决方案2】:

您不能这样做,因为在 lambda 表达式处该类还不是一个完整的类型。

[class.mem]

6 一个类的完整类上下文是一个

  • 函数体([dcl.fct.def.general]),

  • 默认参数,

  • noexcept 说明符,或

  • 默认成员初始化器

在类的成员规范内。 [注:一个完整​​的类 嵌套类的上下文也是任何的完整类上下文 封闭类,如果嵌套类定义在 封闭类的成员规范。 ——尾注]

7 类被认为是完全定义的对象类型 ([basic.types]) (或完整类型)在结束 } 的 类说明符。该类在其范围内被认为是完整的 完整的类上下文;否则被认为是不完整的 它自己的类成员规范。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 2014-02-17
    • 2013-05-07
    • 2012-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多