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

How does generic lambda work in C++14?

本文关键字:工作 何工作 lambda C++14 泛型      更新时间:2023-10-16

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

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

代码示例:

auto glambda = [](auto a) { return a; };

泛型lambda是在C++14中引入的。

简单地说,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的泛型?

正如上面的段落所解释的,泛型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的Portland提案:

[](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中引入的通用lambda是成员模板的快捷方式。一个简单的lambda计算任意类型的两个参数的"answers":

[] (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++周刊-Ep 40-从Lambdas继承
  2. 从lambda继承意味着什么
  3. 代码示例