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

时间:2016-10-25 14:19:18

标签: c++ templates c++14 local-class generic-lambda

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

#include <iostream>

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

或自己模仿:

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

编译器似乎在编译时遇到问题:

error: invalid declaration of member template in local class
     

error: a template declaration cannot appear at block scope

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

我找到this qustion,但我认为答案有点过时(即使对于c ++ 11,我也不认为它是真的。)

2 个答案:

答案 0 :(得分:27)

这是core issue 728,它是在通用lambdas之前提交的。

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

template <typename T>
class X {
    template <typename>
    void foo() {
        T t;
    }
};

template <typename T>
auto bar() {
    return [] (auto) {T t;};
};

使用<void>实例化这些模板在第一种情况下会很好,但在第二种情况下会形成错误。为什么在第一种情况下罚款? foo不需要为每个特定的T实例化,而只需要其中一个([temp.res]/(8.1)}。

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

  

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

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

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

  

在潜在评估表达式([basic.def.odr])中命名实体,其中封闭的完整表达式取决于在的到达范围内声明的通用lambda参数λ-表达

也就是说,如果我有一个像[=] (auto x) {return (typename decltype(x)::type)a;}这样的lambda,其中a是一个封闭函数的块范围变量,无论x的成员typedef是否为{不管是否{1}},强制转换将导致void的捕获,因为我们必须在不等待lambda的调用的情况下做出决定。有关此问题的讨论,请参阅original proposal on generic lambdas

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

这是这种约束的最初动机吗?它是在1994年1月到5月之间的某个时间引入的,没有任何论文覆盖它,所以我们只能粗略地了解this paper证明为什么本地类不应该是模板参数的普遍概念:

  

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

也许那时候,人们想要吻。

答案 1 :(得分:3)

  

我认为问题在c ++标准

中存在更多

正确。这在类模板的[temp]中有规定:

  

template-declaration 只能作为命名空间范围或类范围声明出现。

成员模板的

和[temp.mem]:

  

非闭包类型的本地类不应具有成员模板。

  

允许lambdas拥有模板化成员而不是本地结构的原因是什么?

因为一旦我们在C ++ 11中使用了lambdas,就会认为将该概念扩展为具有泛型lambda非常有用。这种语言扩展名为proposalrevised and revised已被采用。

另一方面,还没有提出一个提案(据我所知,从简短的搜索中得知),提出了在本地课程中不需要成员模板的动机。通过一个普通的lambda充分解决。

如果您认为这是一个需要解决的重要问题,请在为本地成员模板的重要性提供深思熟虑的动机之后随意submit a proposal