34

据我了解 - 通用 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++ 标准而不是编译器错误。允许 lambda 具有模板化成员而不是本地结构的原因是什么?

我找到了这个 qustion,但我认为答案有点过时(我认为即使对于 c++11 也是如此)。

4

2 回答 2

28

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

您提到了泛型 lambda,它们与具有相应 member 的本地类相同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 隐式捕获,如果它......</p>

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

也就是说,如果我有一个类似 的 lambda [=] (auto x) {return (typename decltype(x)::type)a;}a那么封闭函数中的一些块范围变量在哪里,无论x' 的成员 typedef 是否为 for void,强制转换都会导致捕获a,因为我们必须在不等待的情况下决定这一点用于调用 lambda。有关此问题的讨论,请参阅关于通用 lambdas 的原始提案

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


这是这个约束的最初动机吗?它是在 1994 年 1 月到 5 月之间的某个时间引入的,没有论文涵盖它,所以我们只能从这篇论文中关于为什么本地类不应成为模板参数的理由中大致了解流行的概念:

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

也许那时,一个人想亲吻。

于 2016-10-25T15:28:08.977 回答
3

我认为问题更多在于 c++ 标准

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

模板声明只能作为命名空间范围或类范围声明出现。

和 [temp.mem] 用于成员模板:

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


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

因为一旦我们在 C++11 中使用了 lambda,就认为将这个概念扩展为具有通用 lambda 会非常有用。有一个关于这种语言扩展的提案,该提案经过修订 和修订并获得通过。

另一方面,还没有提出提案(据我通过简短的搜索了解到),该提案阐明了在本地类中需要成员模板的动机,而通用 lambda 无法充分解决这些问题.

如果您认为这是一个需要解决的重要问题,请在考虑本地成员模板为何重要的深思熟虑的动机后随时提交提案。

于 2016-10-25T15:23:36.870 回答