通用 lambda 在 C++14 标准中如何工作(auto
关键字作为参数类型)?
它是基于 C++ 模板,其中为每个不同的参数类型编译器生成一个具有相同主体但替换类型的新函数(编译时多态性)还是更类似于 Java 的泛型(类型擦除)?
代码示例:
auto glambda = [](auto a) { return a; };
通用 lambda 在C++14
.
简单地说,由 lambda 表达式定义的闭包类型将具有模板化调用运算符,而不是 lambda 的常规非模板调用运算符C++11
(当然,auto
在参数列表中至少出现一次时)。
所以你的例子:
auto glambda = [] (auto a) { return a; };
将创建glambda
这种类型的实例:
class /* unnamed */
{
public:
template<typename T>
T operator () (T a) const { return a; }
};
C++14 标准草案 n3690 的第 5.1.2/5 段指定了如何定义给定 lambda 表达式的闭包类型的调用运算符:
非泛型 lambda 表达式的闭包类型具有公共内联函数调用运算符 (13.5.4),其参数和返回类型分别由 lambda 表达式的参数声明子句和尾随返回类型描述。对于通用 lambda,闭包类型有一个公共内联函数调用运算符成员模板 (14.5.2),其模板参数列表由一个发明的类型模板参数组成,用于 lambda 的参数声明子句中每次出现的 auto,按出场顺序. 如果相应的参数声明声明了函数参数包(8.3.5),则发明的类型模板参数是参数包。函数调用运算符模板的返回类型和函数参数派生自 lambda 表达式的尾随返回类型和参数声明子句,方法是将参数声明子句的 decl 说明符中每次出现的 auto 替换为名称相应的发明模板参数。
最后:
它是否类似于模板,其中为每个不同的参数类型编译器生成具有相同主体但类型更改的函数,还是更类似于 Java 的泛型?
如上段所述,通用 lambda 只是具有模板化调用运算符的独特、未命名仿函数的语法糖。那应该回答你的问题:)
不幸的是,它们不是 C++11 ( http://ideone.com/NsqYuq ) 的一部分:
auto glambda = [](auto a) { return a; };
int main() {}
使用 g++ 4.7:
prog.cpp:1:24: error: parameter declared ‘auto’
...
但是,它可能在 C++14 中实现的方式根据通用 lambdas 的波特兰提案:
[](const& x, & y){ return x + y; }
这将在很大程度上产生一个匿名仿函数类的通常创建,但是由于缺少类型,编译器将发出一个模板化成员 - operator()
:
struct anonymous
{
template <typename T, typename U>
auto operator()(T const& x, U& y) const -> decltype(x+y)
{ return x + y; }
};
或者根据更新的提案Proposal for Generic (Polymorphic) Lambda Expressions
auto L = [](const auto& x, auto& y){ return x + y; };
--->
struct /* anonymous */
{
template <typename T, typename U>
auto operator()(const T& x, U& y) const // N3386 Return type deduction
{ return x + y; }
} L;
所以是的,对于参数的每一个排列,都会出现一个新的实例化,但是,该仿函数的成员仍然是共享的(即捕获的参数)。
这是一个提议的 C++14 特性(不在 C++11 中),与模板相似(甚至等效)。例如,N3559提供了以下示例:
例如,这个包含通用 lambda 表达式的语句:
auto L = [](const auto& x, auto& y){ return x + y; };
可能会导致创建闭包类型,以及行为类似于以下结构的对象:
struct /* anonymous */ { template <typename T, typename U> auto operator()(const T& x, U& y) const // N3386 Return type deduction { return x + y; } } L;