为什么允许使用通用 lambda 而不允许使用模板化方法的嵌套结构?
Why generic lambdas are allowed while nested structs with templated methods aren't?
据我了解 - 通用 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
and
error: a template declaration cannot appear at block scope
我认为问题出在 C++ 标准中,而不是编译器错误中。允许 lambda 具有模板化成员而不是本地结构的原因是什么?
我找到了 this qustion,但我认为答案有点过时(我认为即使对于 c++11 也是如此)。
I assume the problem lays more in c++ standard
正确。 class 模板的 [temp] 中规定:
A template-declaration can appear only as a namespace scope or class scope declaration.
和 [temp.mem] 成员模板:
A local class of non-closure type shall not have member templates.
What are the reasons lambdas are allowed to have templated members and not the local structures?
因为一旦我们在 C++11 中有了 lambda,人们认为将该概念扩展为具有通用 lambda 将非常有用。有一个proposal for such a language extension, which was revised and revised,被采纳了。
另一方面,目前还没有提出一项提案(据我通过简短搜索得知)阐明在本地 classes 中需要成员模板的动机通用 lambda 不能充分解决这个问题。
如果您觉得这是一个需要解决的重要问题,请在对本地成员模板的重要性提出深思熟虑的动机后,随时 submit a proposal。
这是 core issue 728,它是在通用 lambda 出现之前提交的。
您提到了通用 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 的主体是部分实例化的,使用提供的模板参数。这种部分实例化的原因是......
…the lexical scopes used while processing a function definition are fundamentally transient, which means that delaying instantiation of some portion of a function template definition is hard to support.
(Richard Smith) 我们必须实例化足够多的本地 "template" 以使其独立于本地上下文(包括封闭函数模板的模板参数)。
这也与理由有关
[expr.prim.lambda]/13,它要求实体被 lambda 隐式捕获,如果它......
names the entity in a potentially-evaluated expression ([basic.def.odr]) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
也就是说,如果我有一个像 [=] (auto x) {return (typename decltype(x)::type)a;}
这样的 lambda,其中 a
是来自封闭函数的一些块作用域变量,而不管 x
的成员 typedef 是对于 void
与否,转换将导致捕获 a
,因为我们必须在不等待 lambda 调用的情况下决定这一点。有关此问题的讨论,请参阅 original proposal on generic lambdas.
最重要的是,完全推迟成员模板的实例化与(至少一个)主要实现所使用的模型不兼容,并且由于这些是预期的语义,因此未引入该功能。
这是这个限制的最初动机吗?它是在 1994 年 1 月到 5 月之间的某个时候引入的,没有论文涵盖它,所以我们只能从 this paper 对为什么局部 类 不应该是模板参数的理由中大致了解流行的概念:
Class templates and the classes generated from the template are global scope
entities and cannot refer to local scope entities.
也许那时候,有人想亲一口。
据我了解 - 通用 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
and
error: a template declaration cannot appear at block scope
我认为问题出在 C++ 标准中,而不是编译器错误中。允许 lambda 具有模板化成员而不是本地结构的原因是什么?
我找到了 this qustion,但我认为答案有点过时(我认为即使对于 c++11 也是如此)。
I assume the problem lays more in c++ standard
正确。 class 模板的 [temp] 中规定:
A template-declaration can appear only as a namespace scope or class scope declaration.
和 [temp.mem] 成员模板:
A local class of non-closure type shall not have member templates.
What are the reasons lambdas are allowed to have templated members and not the local structures?
因为一旦我们在 C++11 中有了 lambda,人们认为将该概念扩展为具有通用 lambda 将非常有用。有一个proposal for such a language extension, which was revised and revised,被采纳了。
另一方面,目前还没有提出一项提案(据我通过简短搜索得知)阐明在本地 classes 中需要成员模板的动机通用 lambda 不能充分解决这个问题。
如果您觉得这是一个需要解决的重要问题,请在对本地成员模板的重要性提出深思熟虑的动机后,随时 submit a proposal。
这是 core issue 728,它是在通用 lambda 出现之前提交的。
您提到了通用 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 的主体是部分实例化的,使用提供的模板参数。这种部分实例化的原因是......
…the lexical scopes used while processing a function definition are fundamentally transient, which means that delaying instantiation of some portion of a function template definition is hard to support.
(Richard Smith) 我们必须实例化足够多的本地 "template" 以使其独立于本地上下文(包括封闭函数模板的模板参数)。
这也与理由有关 [expr.prim.lambda]/13,它要求实体被 lambda 隐式捕获,如果它......
names the entity in a potentially-evaluated expression ([basic.def.odr]) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
也就是说,如果我有一个像 [=] (auto x) {return (typename decltype(x)::type)a;}
这样的 lambda,其中 a
是来自封闭函数的一些块作用域变量,而不管 x
的成员 typedef 是对于 void
与否,转换将导致捕获 a
,因为我们必须在不等待 lambda 调用的情况下决定这一点。有关此问题的讨论,请参阅 original proposal on generic lambdas.
最重要的是,完全推迟成员模板的实例化与(至少一个)主要实现所使用的模型不兼容,并且由于这些是预期的语义,因此未引入该功能。
这是这个限制的最初动机吗?它是在 1994 年 1 月到 5 月之间的某个时候引入的,没有论文涵盖它,所以我们只能从 this paper 对为什么局部 类 不应该是模板参数的理由中大致了解流行的概念:
Class templates and the classes generated from the template are global scope entities and cannot refer to local scope entities.
也许那时候,有人想亲一口。