实在是觉得此文总是去翻感觉不太好。于是果断转过来了,想看原文的请戳:http://www.wuzesheng.com/?p=2032

本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lambda表达式, function对象和bind机制。之所以把这三块放在一起讲,是因为这三块之间有着非常密切的关系,通过对比学习,加深对这部分内容的理解。在开始之间,首先要讲一个概念,closure(闭包),这个概念是理解lambda的基础。下面我们来看看wikipedia上对于计算机领域的closure的定义:

A closure (also lexical closure, function closure or function value) is a function together with
a referencing environment for the non-local variables of that function.

上面的大义是说,closure是一个函数和它所引用的非本地变量的上下文环境的集合。从定义我们可以得知,closure可以访问在它定义范围之外的变量,也即上面提到的non-local vriables,这就大大增加了它的功力。关于closure的最重要的应用就是回调函数,这也是为什么这里把function, bind和lambda放在一起讲的主要原因,它们三者在使用回调函数的过程中各显神通。下面就为大家一步步接开这三者的神秘面纱。

  • 1. function

我们知道,在C++中,可调用实体主要包括函数,函数指针,函数引用,可以隐式转换为函数指定的对象,或者实现了opetator()的对象(即C++98中的functor)。C++0x中,新增加了一个std::function对象,std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(我们知道像函数指针这类可调用实体,是类型不安全的)。我们来看几个关于function对象的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include < functional>std::function< size_t(const char*)> print_func;/// normal function -> std::function object
size_t CPrint(const char*) { ... }
print_func = CPrint;
print_func("hello world"):/// functor -> std::function object
class CxxPrint
{
public:size_t operator()(const char*) { ... }
};
CxxPrint p;
print_func = p;
print_func("hello world");

在上面的例子中,我们把一个普通的函数和一个functor赋值给了一个std::function对象,然后我们通过该对象来调用。其它的C++中的可调用实体都可以像上面一样来使用。通过std::function的包裹,我们可以像传递普通的对象一样来传递可调用实体,这样就很好解决了类型安全的问题。了解了std::function的基本用法,下面我们来看一些使用过程中的注意事项:

  • (1)关于可调用实体转换为std::function对象需要遵守以下两条原则:
    a. 转换后的std::function对象的参数能转换为可调用实体的参数
    b. 可高用实体的返回值能转换为std::function对象的(这里注意一下,所有的可调用实体的返回值都与返回void的std::function对象的返回值兼容)。
  • (2)std::function对象可以refer to满足(1)中条件的任意可调用实体
  • (3)std::function object最大的用处就是在实现函数回调,使用者需要注意,它不能被用来检查相等或者不相等
  • 2. bind

bind是这样一种机制,它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体,这种机制在回调函数的使用过程中也颇为有用。C++98中,有两个函数bind1st和bind2nd,它们分别可以用来绑定functor的第一个和第二个参数,它们都是只可以绑定一个参数。各种限制,使得bind1st和bind2nd的可用性大大降低。C++0x中,提供了std::bind,它绑定的参数的个数不受限制,绑定的具体哪些参数也不受限制,由用户指定,这个bind才是真正意义上的绑定,有了它,bind1st和bind2nd就没啥用武之地了,因此C++0x中不推荐使用bind1st和bind2nd了,都是deprecated了。下面我们通过例子,来看看bind的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include < functional>int Func(int x, int y);
auto bf1 = std::bind(Func, 10, std::placeholders::_1);
bf1(20); ///< same as Func(10, 20)class A
{
public:int Func(int x, int y);
};A a;
auto bf2 = std::bind(&A::Func, a, std::placeholders::_1, std::placeholders::_2);
bf2(10, 20); ///< same as a.Func(10, 20)std::function< int(int)> bf3 = std::bind(&A::Func, a, std::placeholders::_1, 100);
bf3(10); ///< same as a.Func(10, 100)

上面的例子中,bf1是把一个两个参数普通函数的第一个参数绑定为10,生成了一个新的一个参数的可调用实体体; bf2是把一个类成员函数绑定了类对象,生成了一个像普通函数一样的新的可调用实体; bf3是把类成员函数绑定了类对象和第二个参数,生成了一个新的std::function对象。看懂了上面的例子,下面我们来说说使用bind需要注意的一些事项:

  • (1)bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数,是pass-by-value的
  • (2)对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。placeholder是pass-by-reference的
  • (3)bind的返回值是可调用实体,可以直接赋给std::function对象
  • (4)对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的
  • (5)类的this可以通过对象或者指针来绑定
  • 3. lambda

讲完了function和bind, 下面我们来看lambda。有python基础的朋友,相信对于lambda不会陌生。看到这里的朋友,请再回忆一下前面讲的closure的概念,lambda就是用来实现closure的东东。它的最大用途也是在回调函数,它和前面讲的function和bind有着千丝万缕的关系。下面我们先通过例子来看看lambda的庐山真面目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
vector< int> vec;
/// 1. simple lambda
auto it = std::find_if(vec.begin(), vec.end(), [](int i) { return i > 50; });
class A
{
public:bool operator(int i) const { return i > 50; }
};
auto it = std::find_if(vec.begin(), vec.end(), A());/// 2. lambda return syntax
std::function< int(int)> square = [](int i) -> int { return i * i; }/// 3. lambda expr: capture of local variable
{int min_val = 10;int max_val = 1000;auto it = std::find_if(vec.begin(), vec.end(), [=](int i) {return i > min_val && i < max_val; });auto it = std::find_if(vec.begin(), vec.end(), [&](int i) {return i > min_val && i < max_val;});auto it = std::find_if(vec.begin(), vec.end(), [=, &max_value](int i) {return i > min_val && i < max_val;});
}/// 4. lambda expr: capture of class member
class A
{
public:void DoSomething();private:std::vector<int>  m_vec;int               m_min_val;int               m_max_va;
};/// 4.1 capture member by this
void A::DoSomething()
{auto it = std::find_if(m_vec.begin(), m_vec.end(), [this](int i){return i > m_min_val && i < m_max_val; });
}/// 4.2 capture member by default pass-by-value
void A::DoSomething()
{auto it = std::find_if(m_vec.begin(), m_vec.end(), [=](int i){return i > m_min_val && i < m_max_val; });
}/// 4.3 capture member by default pass-by-reference
void A::DoSomething()
{auto it = std::find_if(m_vec.begin(), m_vec.end(), [&](int i){return i > m_min_val && i < m_max_val; });
}

上面的例子基本覆盖到了lambda表达的基本用法。我们一个个来分析每个例子(标号与上面代码注释中1,2,3,4一致):

  • (1)这是最简单的lambda表达式,可以认为用了lambda表达式的find_if和下面使用了functor的find_if是等价的
  • (2)这个是有返回值的lambda表达式,返回值的语法如上面所示,通过->写在参数列表的括号后面。返回值在下面的情况下是可以省略的:
    a. 返回值是void的时候
    b. lambda表达式的body中有return expr,且expr的类型与返回值的一样
  • (3)这个是lambda表达式capture本地局部变量的例子,这里三个小例子,分别是capture时不同的语法,第一个小例子中=表示capture的变量pass-by-value, 第二个小拿出中&表示capture的变量pass-by-reference,第三个小例子是说指定了default的pass-by-value, 但是max_value这个单独pass-by-reference
  • (4)这个是lambda表达式capture类成员变量的例子,这里也有三个小例子。第一个小例子是通过this指针来capture成员变量,第二、三个是通过缺省的方式,只不过第二个是通过pass-by-value的方式,第三个是通过pass-by-reference的

分析完了上面的例子,我们来总结一下关于lambda表达式使用时的一些注意事项:

  • (1)lambda表达式要使用引用变量,需要遵守下面的原则:
    a. 在调用上下文中的局部变量,只有capture了才可以引用(如上面的例子3所示)
    b. 非本地局部变量可以直接引用
  • (2)使用者需要注意,closure(lambda表达式生成的可调用实体)引用的变量(主要是指针和引用),在closure调用完成之前,必须保证可用,这一点和上面bind绑定参数之后生成的可调用实体是一致的
  • (3)关于lambda的用处,就是用来生成closure,而closure也是一种可调用实体,所以可以通过std::function对象来保存生成的closure,也可以直接用auto

通过上面的介绍,我们基本了解了function, bind和lambda的用法,把三者结合起来,C++将会变得非常强大,有点函数式编程的味道了。最后,这里再补充一点,对于用bind来生成function和用lambda表达式来生成function, 通常情况下两种都是ok的,但是在参数多的时候,bind要传入很多的std::placeholders,而且看着没有lambda表达式直观,所以通常建议优先考虑使用lambda表达式。

转载于:https://www.cnblogs.com/slysky/p/3822650.html

【转帖】漫话C++0x(四) —- function, bind和lambda相关推荐

  1. C++ function bind以及lamda表达式

    本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lambda表达式, function对象和bind机制.之所以把这三块放在一起讲,是因为这三块之间有着非常密切的关系,通过对比学习,加深对 ...

  2. 【转载】C++ function、bind和lambda表达式

    本篇随笔为转载,原贴地址:C++ function.bind和lambda表达式. 本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lambda表达式, function对象和bind机制 ...

  3. boost::function模块boost::lambda::bind用法的测试程序

    boost::function模块boost::lambda::bind用法的测试程序 实现功能 C++实现代码 实现功能 boost::function模块boost::lambda::bind用法 ...

  4. boost::function/bind

    boost::function/bind boost::function 头文件:<boost/function.hpp> boost::function是一个函数模板,可以代替具有相同返 ...

  5. C++ 类的成员函数指针 ( function/bind )

    这个概念主要用在C++中去实现"委托"的特性. 但现在C++11 中有了 更好用的function/bind 功能.但对于类的成员函数指针的概念我们还是应该掌握的. 类函数指针 就 ...

  6. 函数指针amp;绑定: boost::functoin/std::function/bind

    see link: https://isocpp.org/wiki/faq/pointers-to-members function vs template: http://stackoverflow ...

  7. 【C++】C++11新特性——可变参数模板|function|bind

    文章目录 一.可变参数模板 1.1 可变参数的函数模板 1.2 递归函数方式展开参数包 1.3 逗号表达式展开参数包 1.4 empalce相关接口函数 二.包装器function 2.1 funct ...

  8. 关于0x3f3f3f3f(0x四个3f)

    在之前一道最小生成树问题中遇到过,我按照以前的习惯把INF定义为10亿,然后初始化数组为最大值,然后输入连通的路+value,最后值仍然为INF的即为不通的.但是这里出问题了,INF定义为10亿的话, ...

  9. re:Invent大会第四天:为什么Lambda值得你更多关注?

    2018年11月29日的拉斯维加斯,AWS re:Invent大会进入第四天,上午照例由AWS CTO Werner Vogels带来主题演讲. 从主题演讲之前到主题演讲之后,改变最大的产品毫无疑问就 ...

最新文章

  1. 德国科学院院士:传统企业寻求变革,向智能制造靠近
  2. lambda表达式可以用来声明_Lambda 的骚操作,你都get到了没
  3. stdthread(2)创建
  4. OpenGL天空游戏
  5. 关于手机游戏Ogame
  6. How to Fix “Username is not in the sudoers file. This incident will be reported” in Ubuntu
  7. 神奇的事情--长见识了
  8. Js-01. 语法、关键保留字、变量
  9. Eclipse插件Ant里运用ftp遇到的问题
  10. Linux下的PDF阅读器Foxit
  11. 地震设计反应谱、时程分析法和地震动选取与调整
  12. 芯片数据分析笔记【03】 | GEO数据库使用教程及在线数据分析工具
  13. sap成本流怎么看_SAP标准成本核算体系
  14. 深度学习关于分布式任务调度平台XXL-JOB框架详解
  15. 求助 matlab 2015b运行cat12出现内部错误闪退
  16. Macbook windows 10系统下录屏软件无法录制系统声音的问题
  17. cbac式_abca式的成语
  18. 自动化立体仓库系统(Automated Storage and Retrieval System)
  19. 【转】60系列应用的全屏处理
  20. Kindeditor.NET 实现多图上传保存

热门文章

  1. 弈剑行:几经曲折却遇开服宕机,克服困难单机上线,他们不妥协
  2. jsp的内置对象有哪些
  3. IT界含金量高的认证考试
  4. 计算某一段程序消耗的内存和时间【Java】
  5. oracle中minus
  6. 出现“ORA-28000:the account is locked”的解决办法
  7. Link Cut Tree学习笔记
  8. java基础之访问控制符
  9. WebForms UnobtrusiveValidationMode 需要“jquery”ScriptResourceMapping
  10. c语言 sdk,适用于 C 语言的 Azure IoT 设备 SDK