据我所知 - 泛型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,我也不认为它是真的。)
答案 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非常有用。这种语言扩展名为proposal,revised and revised已被采用。
另一方面,还没有提出一个提案(据我所知,从简短的搜索中得知),提出了在本地课程中不需要成员模板的动机。通过一个普通的lambda充分解决。
如果您认为这是一个需要解决的重要问题,请在为本地成员模板的重要性提供深思熟虑的动机之后随意submit a proposal。