泛型 lambda 在 C + + 14中是如何工作的?

泛型 lambda 在 C + + 14标准中是如何工作的(auto关键字作为参数类型) ?

它是基于 C + + 模板,编译器为每个不同的参数类型生成一个具有相同主体但替换了类型(编译时多态性)的新函数,还是更类似于 Java 的泛型(类型擦除) ?

代码示例:

auto glambda = [](auto a) { return a; };
53289 次浏览

C++14中引入了通用的 lambdas。

简单地说,lambda 表达式定义的闭包类型将具有 模板调用操作符,而不是 C++11的 lambdas 的常规、非模板调用操作符(当然,当 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 的泛型?

正如上面的段落所解释的,泛型 lambdas 只是具有模板化调用操作符的唯一未命名函数的语法糖。这应该能回答你的问题:)

不幸的是 ,它们不是 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; }
};

或者按照新的建议 泛型(多态) 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;

因此,是的,对于每个参数的排列,都会出现一个新的实例化,但是,该函数的成员仍然是共享的(即捕获的参数)。

这是一个与模板类似(甚至等价)的 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;

从书中,C + + 模板: 完整指南(第2版)第5.5.2条

5.5.2通用 Lambdas 和成员模板

注意,C + + 14引入的通用 lambdas 是成员模板的快捷方式。一个简单的 lambda 计算任意类型两个参数的“和”:

[] (auto x, auto y) {
  return x + y;
}

是下列类的默认构造对象的快捷方式:

class SomeCompilerSpecificName {
  public:
    SomeCompilerSpecificName();  // constructor only callable by compiler
    template<typename T1, typename T2>
    auto operator() (T1 x, T2 y) const {
      return x + y;
    }
};

这意味着对于泛型 lambda,编译器正在生成一个模板化类。因此,对于 auto,模板的类型推导规则将适用。

一个有趣的推论是,你可以从 lambdas 继承。

更多关于从 lambdas 继承的资料:

  1. C + + 每周-第40期-继承自 Lambdas
  2. 从 Lambda 继承意味着什么?
  3. 代码样本