为什么在使用模板化方法的嵌套结构时不允许使用泛型lambda?

W.F*_*.F. 32 c++ templates local-class generic-lambda c++14

据我所知 - 泛型lambda被转换为具有模板化的局部范围结构的对象operator().这使得通用lambda非常强大且易于使用的工具.另一方面,可以创建嵌套到函数中的结构,但是当结构具有模板化成员时,例如:

#include <iostream>

int main() {
    struct inner {
    template <class T>
       void operator()(T &&i) { }
    };
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

或者自己模仿:

int main() {
    template <class T>
    struct inner {
       void operator()(T &&i) { }
    };
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译器似乎有编译它的问题:

error: invalid declaration of member template in local class
Run Code Online (Sandbox Code Playgroud)

error: a template declaration cannot appear at block scope
Run Code Online (Sandbox Code Playgroud)

我认为问题在c ++标准中比在编译器bug中更多.lambdas被允许拥有模板化成员而不是本地结构的原因是什么?

我发现了这个问题,但我认为答案有点过时(即使对于c ++ 11,我也不认为这是真的).

Col*_*mbo 27

这是核心问题728,它是在通用lambda之前提交的.

您提到了通用lambdas,它们与具有相应成员的本地类相同template operator().但是,它们实际上并非如此,并且差异与实施特征有关.考虑

template <typename T>
class X {
    template <typename>
    void foo() {
        T t;
    }
};
Run Code Online (Sandbox Code Playgroud)

template <typename T>
auto bar() {
    return [] (auto) {T t;};
};
Run Code Online (Sandbox Code Playgroud)

<void>在第一种情况下实例化这些模板将是正常的,但在第二种情况下是不正确的.为什么在第一种情况下罚款?foo不需要为每个特定实例化T,而只需要其中一个(这将是[temp.res] /(8.1)).

为什么在第二种情况下形成不良?通用lambda的主体使用提供的模板参数进行实例化 - 部分 - .这种部分实例化的原因是......

...处理函数定义时使用的词法范围基本上是暂时的,这意味着很难支持延迟函数模板定义某些部分的实例化.

(Richard Smith)我们必须实例化足够的本地"模板",使其独立于本地上下文(包括封闭函数模板的模板参数).

这也与[expr.prim.lambda]/13的基本原理有关 ,它要求一个实体被lambda隐式捕获,如果它......

在潜在评估表达式([basic.def.odr])中命名实体,其中封闭的full-expression依赖于在lambda-expression的到达范围内声明的泛型lambda参数.

也就是说,如果我有一个像lambda一样的[=] (auto x) {return (typename decltype(x)::type)a;}地方,a来自封闭函数的某个块范围变量,无论是否x成员typedef是否void存在,强制转换将导致捕获a,因为我们必须在不等待的情况下做出决定为了调用lambda.有关此问题的讨论,请参阅有关通用lambdas原始提议.

底线是完全推迟成员模板的实例化与(至少一个)主要实现所使用的模型不兼容,并且由于这些是预期的语义,因此未引入该特征.


那是这种约束的最初动机吗?它是在1994年1月至5月的某个时间引入的,没有任何论文覆盖它,因此我们只能粗略地了解本文中为什么本地类不应该是模板参数的理由:

类模板和从模板生成的类是全局范围实体,不能引用本地范围实体.

也许那时候,人们想要亲吻.

  • @Barry我事先就知道了,因为我开始为它写一篇论文 (5认同)
  • @Columbo不是真的:`template <class T> struct C {template <class> void f(){T t; }}; C <void> c;`格式正确; `template <class T> void f(){[](auto &&){T t; }; } f <void>();`不是. (2认同)