C++11之Lambda特性探析

简介: C++11之Lambda特性探析.pdf 目录 目录 1 1. 什么是Lambda? 1 2. 语法格式 1 2.1. 语法格式 1 2.

img_e25d4fb2f8de1caf41a735ec53088516.pngC++11之Lambda特性探析.pdf

目录

目录 1

1. 什么是Lambda 1

2. 语法格式 1

2.1. 语法格式 1

2.2. 最简定义 2

3. 应用示例 2

4. capture列表 3

4.1. 基本形式 3

4.2. 注意事项 3

5. 对比仿函数 3

6. 对比函数指针 4

7. LamdbaSTL 4

8. 参考资料 5

 

1. 什么是Lambda

Lambda['l?md?]表达式是一个没有函数名的匿名函数,基于数学中的希腊字母λ演算得名。

2. 语法格式

2.1. 语法格式

Lambda函数的语法定义为:[capture] (parameters) mutable ->return_type { statement }。

 

1) capture

捕获列表,可以为空,但[]是必须的不能省略,编译器需要根据它来判断是否为Lambda函数。这个是整个Lambda中相对新鲜和复杂的地方,后面专节介绍

区别于普通函数,捕获列表的意义在于:Lambda可直接访问父作用域中捕获列表所指定的变量,普通函数或类成员函数除了参数和类成员外,是不能访问父作用域(如调用它的父函数)中其它变量的。。

2) parameters

参数列表,和普通的函数没什么两样,如果没有参数,写可以写成(),不同于[],空的()也可省略。

3) mutable

修饰符,默认Lambda函数为const函数。

4) ->return_type

函数返回类型,在无返回值,或返回值可以推导出的情况下,可以省略。

5) statement

函数体,和普通函数体没有什么不同,但是除了可以使用参数外,还可以使用capture中所指定的变量。

2.2. 最简定义

通过以上规则,显然可以发现最简的Lambda函数定义:[] {};,这是一个什么也不做的空Lambda函数。

3. 应用示例

// 编译:g++ -std=c++11 -g -o x x.cpp

// 示例在g++ 4.8.2上编译通过

#include 

 

int main()

{

    int boys = 4;  // 男生人数

    int girls = 3; // 女生人数

    

    // 计算男生和女生总人数,

    // 这里必须用上C++11新定义的auto,

    // total_child类似于指向函数的指针了,并带两个int类型的参数

    auto total_child = [](int x, int y) -> int

    {

        return x + y;

    };

    

    // 调用

    int x = total_child(girls, boys);

    printf("%d\n", x);

    

    return 0;

}

4. capture列表

4.1. 基本形式

这个是C++11 Lambda中非常有趣的地方,使用[]标识,有如下几种形式:

1) [var] 表示以值传递方式捕获变量var

2) [=] 表示以值传递方式捕获父作用域的所有变量,包括this

3) [&var] 表示以引用传递方式捕获变量var

4) [&] 表示以引用传递方式捕获父作用域的所有变量,包括this

5) [this] 表示以值传递方式捕获this

 

除以上5种基本形式化,还支持组合,如:

1) [=, &a, &b] 表示以引用传递方式捕获变量a和变量b,以值传递方式捕获父作用域的其它所有变量

2) [&, a, this] 表示以值传递方式捕获父作用域的变量athis,以引用传递方式捕获其它所有变量

4.2. 注意事项

在上一节,可以看到捕获的几种基本形式,可以组合同时使用,但这里有个约束:不允许重复传递,比如:

1) [=, a] 由于=表示以值传递方式捕获所有父作用域的变量,a就和它重复了,所以产生了语法错误

2) [&, &this] 同理,&this也重复了,同样是语法错误。

5. 对比仿函数

在C++中,仿函数就是用一个类来模仿含糊,虽然用得不多,但有时却需要它,比如自定义map的比较函数等场合。下面是一个仿函数示例:

// 编译:g++ -std=c++11 -g -o y y.cpp

// 示例在g++ 4.8.2上编译通过

#include 

 

// 定义一个仿函数

class functor

{

public:

    // 仿函数的特点就是重载了类的()操作符

    int operator ()(int x, int y) const

    {

        return x + y;

    }

};

 

int main()

{

    int boys = 4;

    int girls = 3;

    

    // 使用仿函数

    functor total_child;

    int x = total_child(girls, boys);

    printf("%d\n", x);

    

    return 0;

}

 

由于仿函数是借助classstruct来实现的,因此它可以有类成员,仿函数被广泛的应用在STL的实现当中,它和Lambda函数相似,但要复杂一点。

6. 对比函数指针

Lambda函数并非函数指针,在C++11标准中将它定义为闭包(Closure)的类,每个Lambda会产生一个闭包类型的临时对象(右值)。

虽然如此,但C++11标准允许Lambda表达式向函数指针的转换,前提是Lambda函数没有捕获任何变量,而且函数指针的原型必须和Lambda函数有相同的调用方式。

7. LamdbaSTL

Lamdba函数和STL中的for_each结合,是最典型的应用场景,它相比其它方式都显得更为简约:

// 编译:g++ -std=c++11 -g -o z z.cpp

// 示例在g++ 4.8.2上编译通过

#include 

#include 

#include 

using namespace std;

 

void print(int i)

{

    printf("%d\n", i);

}

 

int main()

{

    vector nums;

    nums.push_back(2);

    nums.push_back(0);

    nums.push_back(1);

    nums.push_back(4);

 

    // 传统的for循环

    for (auto iter=nums.begin(); iter!=nums.end(); ++iter)

    {

        printf("%d\n", *iter);

    }

 

    // 使用函数指针

    for_each(nums.begin(), nums.end(), print);

 

    // 使用Lamdba函数

    for_each(nums.begin(), nums.end(), [=](int i)

    {

        printf("%d\n", i);

    });

 

    return 0;

}

8. 参考资料

推荐进一步阅读:《深入理解C++11C++11新特性解析与应用》。

 

相关文章
|
27天前
|
编译器 C++ 开发者
C++一分钟之-C++20新特性:模块化编程
【6月更文挑战第27天】C++20引入模块化编程,缓解`#include`带来的编译时间长和头文件管理难题。模块由接口(`.cppm`)和实现(`.cpp`)组成,使用`import`导入。常见问题包括兼容性、设计不当、暴露私有细节和编译器支持。避免这些问题需分阶段迁移、合理设计、明确接口和关注编译器更新。示例展示了模块定义和使用,提升代码组织和维护性。随着编译器支持加强,模块化将成为C++标准的关键特性。
60 3
|
1月前
|
编译器 C语言 C++
C++一分钟之-C++11新特性:初始化列表
【6月更文挑战第21天】C++11的初始化列表增强语言表现力,简化对象构造,特别是在处理容器和数组时。它允许直接初始化成员变量,提升代码清晰度和性能。使用时要注意无默认构造函数可能导致编译错误,成员初始化顺序应与声明顺序一致,且在重载构造函数时避免歧义。利用编译器警告能帮助避免陷阱。初始化列表是高效编程的关键,但需谨慎使用。
29 2
|
2月前
|
存储 编译器 C语言
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题(下)
从C语言到C++_34(C++11_下)可变参数+ lambda+function+bind+笔试题
40 5
|
8天前
|
安全 编译器 C++
C++一分钟之-泛型Lambda表达式
【7月更文挑战第16天】C++14引入泛型lambda,允许lambda接受任意类型参数,如`[](auto a, auto b) { return a + b; }`。但这也带来类型推导失败、隐式转换和模板参数推导等问题。要避免这些问题,可以明确类型约束、限制隐式转换或显式指定模板参数。示例中,`safeAdd` lambda使用`static_assert`确保只对算术类型执行,展示了一种安全使用泛型lambda的方法。
16 1
|
21天前
|
数据安全/隐私保护 C++
|
1月前
|
算法 编译器 C++
C++一分钟之—Lambda表达式初探
【6月更文挑战第22天】C++的Lambda表达式是匿名函数的快捷方式,增强函数式编程能力。基本语法:`[capture](params) -> ret_type { body }`。例如,简单的加法lambda:`[](int a, int b) { return a + b; }`。Lambda可用于捕获外部变量(值/引用),作为函数参数,如在`std::sort`中定制比较。注意点包括正确使用捕获列表、`mutable`关键字和返回类型推导。通过实践和理解这些概念,可以写出更简洁高效的C++代码。
36 13
|
28天前
|
安全 JavaScript 前端开发
C++一分钟之-C++17特性:结构化绑定
【6月更文挑战第26天】C++17引入了结构化绑定,简化了从聚合类型如`std::tuple`、`std::array`和自定义结构体中解构数据。它允许直接将复合数据类型的元素绑定到单独变量,提高代码可读性。例如,可以从`std::tuple`中直接解构并绑定到变量,无需`std::get`。结构化绑定适用于处理`std::tuple`、`std::pair`,自定义结构体,甚至在范围for循环中解构容器元素。注意,绑定顺序必须与元素顺序匹配,考虑是否使用`const`和`&`,以及谨慎处理匿名类型。通过实例展示了如何解构嵌套结构体和元组,结构化绑定提升了代码的简洁性和效率。
40 5
|
1月前
|
C++
C++语言的lambda表达式
C++从函数对象到lambda表达式以及操作参数化
|
21天前
|
存储 安全 编译器
|
2月前
|
编译器 C语言 C++
C++的基本特性和语法
C++的基本特性和语法
31 1