通用Lambda在C ++ 14中如何工作?


114

通用Lambda如何auto在C ++ 14标准中工作(关键字作为参数类型)?

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

代码示例:

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

6
固定为C ++ 14,最初使用的是有问题的C ++ 11
sasha.sochka,2013年

Answers:


130

通用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表达式的parameter-declaration-clause和Trailing-return-type描述。对于一般的lambda,闭包类型具有一个公共的内联函数调用操作员成员模板(14.5.2),该模板的template-parameter-list由一个发明的类型template-parameter组成,用于lambda的parameter-declaration-clause中每次出现auto时,按出场顺序。如果相应的参数声明声明了功能参数包(8.3.5),则本发明的类型template-parameter是参数包。函数调用运算符模板的返回类型和函数参数是从lambda表达式的尾随返回类型和参数声明子句派生的,方法是将参数声明子句的decl-specifier中的auto每次出现替换为相应的发明模板参数。

最后:

它是否类似于模板,模板针对每个不同的参数类型,编译器生成具有相同主体但类型已更改的函数,还是更类似于Java的泛型?

如以上段落所述,泛型lambda只是具有模板化调用运算符的唯一未命名函子的语法糖。那应该回答你的问题:)


7
但是,它们还允许使用模板方法在本地定义类。哪个是新的。
Yakk-Adam Nevraumont

2
@Yakk:函数本地模板的限制是否已经与C ++ 11一起被取消?
塞巴斯蒂安·马赫

2
@phresnel:是的,没有取消限制
Andy Prowl

1
@AndyProwl:我意识到我的错误。实际上解除的是使用局部类型作为模板参数(如int main () { struct X {}; std::vector<X> x; }
Sebastian Mach 2013年

1
@phresnel:是的,这确实发生了变化
Andy Prowl

25

不幸的是,它们不属于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
...

但是,根据通用lambda波特兰建议,可以在C ++ 14中实现它的方式:

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

这将最大程度地产生通常创建匿名仿函数类的方法,但是由于缺乏类型,编译器将发出模板化member- 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;

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


6
允许删除类型说明符的建议完全荒唐。
Lightness Races in Orbit

他们加入了g ++-4.9。您需要提供-std=c++1y
emsr

我没有意识到ideone还没有gcc-4.9和C ++ 14。
emsr

问题:这auto与经典汽车有相同的扣除规则吗?如果我们指的是模板化类比,则意味着auto不是auto,它与模板类型推导是相同的规则。然后的问题是:模板扣除等于auto吗?
v.oddou 2014年

@ v.oddou:“经典汽车”很好。对我来说,“经典自动”的意思是“堆栈变量”,并且曾经与staticregister:: 相对使用auto。实际上,lambda将在内部由functor类替换,并且auto参数表示template <T> ... (T ...)将被发出。
塞巴斯蒂安·马赫2014年

17

这是提议的C ++ 14功能(不在C ++ 11中),与模板相似(甚至等效)。例如,N3559提供了以下示例:

例如,以下通用lambda-expression包含语句:

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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.