本文将详解Lambda函数从定义到学习和使用,涉及一些不为人知的事情,如LIFE-立即调用的函数表达式,Lambda的类型。相信你已经起了兴趣,那就开始阅读吧。

作者 | Vishal Chovatiya

译者 | 苏本如,责编 | maozz

出品 | CSDN(ID:CSDNnews)

以下为译文:

Lambda函数是C++ 11中引入的现代C++的一个直观概念,因此在互联网上可以找到大量的关于Lambda函数的文章。但是仍然有一些不为人知的事情(如LIFE-立即调用的函数表达式,Lambda的类型等等)鲜有人谈论。因此,在这篇文章里,我不仅要向你展示C++中的Lambda函数,同时还要介绍它的内部工作机制,以及Lambda函数的其他方方面面。

这篇文章的标题有点误导人。因为Lambda并不总是转化为函数指针。实际上它是一个表达式(确切地说是唯一的闭包)。为了简单起见,在这篇文章中,我会一直互换使用Lambda函数和Lambda表达式。

什么是Lambda函数?

Lambda函数是简短的代码片段,它:

不值得命名(匿名的、未被命名的、一次性的,等等,无论你怎么称呼它),

也不能重复使用。

换句话说,它只是一种糖衣语法(syntactic sugar)。Lambda函数的语法定义如下:

[ capture list ] (parameters) -> return-type

{ method definition

}

编译器通常会计算Lambda函数本身的返回类型。因此,我们不需要显式地给它指定一个尾置返回类型,如-> return-type。

但在一些复杂的情况下,编译器无法推断返回类型,这时候我们就需要给它指定一个返回类型。

为什么我们要使用Lambda函数?

C++包含许多有用的通用函数,如std::for_each,它们可以很方便。不幸的是,它们的使用有时也很麻烦,特别是如果你想应用的函子是特定函数的唯一函子的话。以下面的代码为例:

struct print

{

void operator(int element)

{

cout << element << endl;

}

};

int main(void)

{

std::vector v = {1, 2, 3, 4, 5};

std::for_each(v.begin, v.end, print);

return 0;

}

如果你只是在特定的地方使用一次print,那么仅仅为了做一些琐碎的和一次性的事情而编写一个完整的类,就显得有些过犹不及了。

对于上面的这种情形,使用内联代码会更合适,这可以通过Lambda函数来实现,如下所示:

std:for_each(v.begin, v.end, (int element) { cout << element << endl; });

Lambda函数内部是如何工作的?

[&i] { std::cout << i; }

// is equivalent to

struct anonymous

{

int &m_i;

anonymous(int &i) : m_i(i) {}

inline auto operator const

{

std::cout << i;

}

};

编译器为每个Lambda函数生成如上所述的唯一闭包。注意,这是Lambda函数的核心所在。

捕获列表将成为闭包中的构造函数的参数,如果将参数按值捕获,那么相应类型的数据成员将在闭包中创建。

此外,可以在Lambda函数的参数中声明变量/对象,它们将成为调用operator函数的参数。

使用Lambda函数的好处

零成本抽象。对!你没有看错。Lambda函数不会降低性能,它的性能和普通的函数一样好。

此外,Lambda函数使代码变得更加紧凑、更加结构化和更富有表现力。

学习Lambda表达式

按引用/值来捕获,代码如下:

int main

{

int x = 100, y = 200;

auto print = [&] { // Capturing object by reference

std::cout << __PRETTY_FUNCTION__ << " : " << x << " , " << y << std::endl;

};

print;

return 0;

}

上面代码的输出如下:

main:: : 100 , 200

在上面的例子中,我在捕获列表中对“&”符号作了注释。它表示按引用来捕获变量x和y。类似地,“=”符号表示按值捕获,它将在闭包中创建相同类型的数据成员,并且将执行copy-assignment操作。

请注意,参数列表是可选的,如果你不向Lambda表达式传递任何参数,则可以省略空括号。

Lambda函数的捕获列表

下表显示了捕获列表中不同用法的含义:

将Lambda函数作为参数传递,代码如下:

template

void f(Functor functor)

{

std::cout << __PRETTY_FUNCTION__ << std::endl;

}

/* Or alternatively you can use this

void f(std::function functor)

{

std::cout << __PRETTY_FUNCTION__ << std::endl;

}

*/

int g { static int i = 0; return i++; }

int main

{

auto Lambda_func = [i = 0] mutable { return i++; };

f(Lambda_func); // Pass Lambda

f(g); // Pass function

}

上面代码的输出如下:

Function Type : void f(Functor) [with Functor = main()::]

Function Type : void f(Functor) [with Functor = int (*)(int)]

你还可以将Lambda函数作为参数传递给其他函数,就像我在上面编写的普通函数一样。

如果你注意到了,这里我在捕获列表中声明了变量i,它将成为数据成员。因此,每次调用Lambda_func时,它都将返回并递增。

捕获Lambda函数中的成员变量或this指针,代码如下:

class Example

{

public:

Example : m_var(10) {}

void func

{

[=] { std::cout << m_var << std::endl; }; // IIFE

}

private:

int m_var;

};

int main

{

Example e;

e.func;

}

也可以使用[this], [=] 或者 [&]来捕获This指针。在任何这些情况下,类中的数据成员(包括private类型的数据成员)都可以像在普通方法中那样被访问。

如果你看到Lambda表达式行,我在Lambda函数声明的末尾使用了额外的 ,这个额外的 用来表示在声明之后立即调用它,它被称为IIFE(立即调用的函数表达式)。

C++的Lambda函数类型

泛型Lambda,代码如下:

const auto l = (auto a, auto b, auto c) {};

// is equivalent to

struct anonymous

{

template

auto operator(T0 a, T1 b, T2 c) const

{

}

};

在C++ 14中引入的泛型Lambda,它可以使用auto标识符捕获参数。

可变泛型Lambda,代码如下:

void print {}

template

void print(const First &first, Rest &&... args)

{

std::cout << first << std::endl;

print(args...);

}

int main

{

auto variadic_generic_Lambda = (auto... param) {

print(param...);

};

variadic_generic_Lambda(1, "lol

c++的lambda表达式捕获this_贯穿 C++ 11 与 C++ 17 的 Lambda 到底是个什么?相关推荐

  1. 贯穿 C++ 11 与 C++ 17 的 Lambda 到底是个什么?

    本文将详解Lambda函数从定义到学习和使用,涉及一些不为人知的事情,如LIFE-立即调用的函数表达式,Lambda的类型.相信你已经起了兴趣,那就开始阅读吧. 作者 | Vishal Chovati ...

  2. lambda表达式——捕获

    lambda表达式 等价于匿名函数对象,又称为"闭包"(closure),更便捷,表达更直接.表达式要素包括: 1:捕获列表 2:参数列表 3:mutable修饰符,表达传值或传引 ...

  3. 10个Java 8 Lambda表达式经典示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表 达式,它将允许我们将行为传到函数里.在J ...

  4. 深入理解Java 8 Lambda表达式(Oracle官方文档版)

    Java 8 问世三年了,9马上也要问世了,所以,嗯,我要开始学8了-- 官方文档:http://docs.oracle.com/javase/tutorial/java/javaOO/lambdae ...

  5. java 拉姆表达式_Java8 lambda表达式10个示例

    Java 8 lambda表达式示例 转自importNew 原文链接 例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现R ...

  6. 学习Kotlin(五)函数与Lambda表达式

    推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...

  7. 这是一个有趣的问题,Java 8 Lambda 表达式被编译成了什么?

    在了解了Java 8 Lambda的一些基本概念和应用后, 我们会有这样的一个问题: Lambda表达式被编译成了什么? 这是一个有趣的问题,涉及到JDK的具体的实现.本文将介绍OpenJDK对Lam ...

  8. java8 lambda python_【学习笔记】java8 Lambda表达式语法及应用

    本文是慕课网大牧莫邪老师的视频教程一课掌握Lambda表达式语法及应用的学习笔记.如果觉得内容对你有用,可以购买老师的课程支持一下,课程价格1元,十分良心了. 1. 课程介绍 2. 为什么引入Lamb ...

  9. C# Lambda表达式 基础

    什么是Lambda 表达式? "Lambda表达式"实际上是一个方法,只不过该方法是一个匿名方法(就是没有名字的方法(函数),就是说只有在定义的时候能调用,在其他地方就不能调用了) ...

最新文章

  1. 获取服务端https证书
  2. HTML5中常用的标签(及标签的属性和作用)
  3. Windows 环境下载安装Docker
  4. 【体验】感谢朋友雪中送炭寄来的便携示波器,便携示波器开箱体验
  5. 可用子网数要不要减2_CCNA最实用的复习知识点(2)
  6. const_cast的使用:添加或去掉const、常量折叠
  7. 前端小白也能快速学会的博客园博客美化全攻略
  8. 如何启动多个WebLogic托管服务器
  9. 三、Numpy数组操作
  10. Rust核心团队前成员Brian Anderson加入PingCAP
  11. 图像算法三:【图像增强--空间域】图像平滑、中值滤波、图像锐化
  12. 在Visual C#中用ListView显示数据记录
  13. Centos6.X 安装MongoDb
  14. [渝粤教育] 浙江大学 物理光学实验及仿真 参考 资料
  15. Java多线程之FutureTask
  16. python3 学习日志 Microsoft Office 编程
  17. Python学习指南——1.常用库说明
  18. 蓝桥杯比赛时间在什么时候_什么时候立冬2020年农历具体时间
  19. 加入洛谷OJ,开通洛谷博客
  20. 什么是MACsec功能?有什么作用?

热门文章

  1. 40-400-030-运维-优化-MySQL入门调优脚本tuning-primer的使用
  2. 【kafka】Failed to allocate.memory within the configed max blocking time
  3. [Flink] Flink运行报错The number of requested virtual cores for application master
  4. 【es】INDEX_CREATED the shard cannot be allocated to the same node a copy of the shard already
  5. Spring : Spring profile 实现多环境支持
  6. registry :分支操作值Archive有什么用?
  7. 95-130-020-源码-source-SourceFunction
  8. CentOS设置网卡成DHCP动态获取IP
  9. Docker简易搭建 ElasticSearch 集群
  10. Java如何实现后端分页