C++primer -lambda表达式与bind

  • lambda表达式:无需头文件

    lambda表达式是一个可调用的代码单元,可以将其理解为一个未命名的内联函数;

    可调用即可以对该对象使用调用运算符。支持调用运算符的对象,包括:重载了调用运算符的类,lambda表达式,函数及函数指针。

    以下是lambda表达式的通用写法:

    [ 捕获列表 ]( 参数列表 ) -> 返回类型{ 函数体内容 }

    例1:[sz](int i)->bool {return sz > i;}  是一个lambda表达式,返回类型是bool值,接收一个参数int i,从外部作用域捕获一个已存在的变量sz。

    例2:int(*)(int, int) f = [](int a, int b){return a+b;};  f(1, 2); // f是一个函数指针,它被绑定到 lambda表达式:[](int a, int b){return a+b;}  上,其返回类型是a+b的结果值的类型int,  f(1, 2) 返回1 + 2的结果。如果lambda表达式中不显式声明返回类型,lambda表达式将根据函数体中的代码推断出返回类型。如果函数体只含一个return语句,则编译器根据返回值的类型推断lambda表达式的返回类型。若函数体不是仅有一条return语句且未显式声明返回类型,那么函数的返回类型为void。

  • lambda的捕获变量:

    捕获变量是外层作用域中,已存在的对象被作为同名参数传递到 lambda 函数体中使用。未声明在参数列表中的、外层作用域中已存在的 变量名,会被编译器自动推断为捕获变量。

    例:int sz = 1; auto f = [sz](int i)->bool {return sz > i;}; // 值捕获局部变量sz, sz的值是1。

  • 捕获列表的第一个参数可以用于声明捕获变量的传递方式,有引用捕获和值捕获两种:
  • 引用捕获:用&表示,此时捕获变量在lambda表达式中的修改将同步改变对应外层作用域中变量的值。

    值捕获:用=表示,捕获变量在lambda表达式内的修改 不改变外层变量的值。

  • 捕获列表的取值:
  • []

    捕获列表空表示不捕获

    [名字列表]

     表示默认进行值捕获

    [&]

     表示引用捕获

    [=]

     表示值捕获

    [&, a, b...]

    除a、b...外的捕获是引用捕获

    [=, a, b...]

    除a、b...外的捕获是值捕获

  • 捕获的注意点:
  • 1、值捕获是在lambda表达式创建时被拷贝:

    捕获变量的初始化发生在lambda表达式被定义之时,在lambda表达式定义的位置,就完成了捕获变量的传参。因此值捕获的变量其值在调用时取的仍旧是lambda表达式初始化时的该变量值。引用捕获由于是对象的引用,其值与对象当前的值一致。

    2、值捕获要求变量必须可以被拷贝;

    3、若函数返回一个lambda表达式,此lambda表达式不能是引用捕获的,因为引用捕获的局部变量可能不存在;

    4、对于一个const变量使用引用捕获要注意不能改变其值。

    lambda表达式的其他注意点:

    1、lambda表达式可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体, 例:[]{ statements; }

    2、在lambda中忽略括号和参数列表等价于指定一个空参数列表。

    3、只能在lambda表达式只有一条返回语句时省略其返回类型:若lambda表达式只有一条return语句,返回类型的声明:->return_type 可以被省略,但一旦lambda表达式有除return之外的语句,省略了返回类型的lambda表达式的返回类型将被编译器自动推断为void。因此只能在lambda表达式只有一条返回语句时省略返回类型。

    bind:定义在头文件<functional>

    bind的通常用法:

    auto newCallable = bind(callable, arg_list);

    bind 函数将一个可调用对象绑定到另一个可调用对象上,作用类似于参数的接口转换器。

    bind函数接受一个可调用对象callable和参数列表arg_list作为参数,返回一个新的可调用对象newCallable 。arg_list将作为callable的实参列表,arg_list列表中的元素可以是一个变量也可以是一个占位符。newCallable有几个占位符,newCallable就接收几个实参。实参将按照占位符的数字值标识的顺序传递给callable作为参数。

    占位符placeholder

    占位符_n 都定义在命名空间placeholder中:应使用using std::placeholdersusing std::placeholders::_1; 在程序中声明。占位符的作用是先占住当前的位置,之后将传入的第n个参数放到这个位置上,n是占位符所标识的数字,如_1将第一个参数放到它所在位置。举例:

  • auto newCallable = bind(add, 6, std::placeholder::1);  中newCallable的第一个参数,会被放到std::placeholder::1的位置,然后得到,bind(add, 6, 参数1) ,bind又将使用参数列表调用add.其结果是调用newCallable(参数1)就是调用add(6, 参数1)。

  • 占位符定义在头文件<functional>中。

  • bind参数次序的实例:

    设x、y、z是三个实参,那么对于using  std::placeholders;  auto newCallable = bind(callable,  _1, "abc" , _3, _2 ); 调用 newCallable(x, y, z) 相当于调用 callable(x, "abc", z, y) ;

    以下示例可说明占位符的次序:

    bind的作用与示例:

    bind 通过将固定参数写在arg_list中,未知参数使用占位符的方式,完成将接口从接收多个参数转为接受更少的参数的作用。

    例:

    为完成通过find_if和check_size找出vector<string>中第一个长度大于6的元素,使用bind:

    bool check_size(const string, string::size_type sz){

        return s.size() >= sz;

    }

    auto check6 = bind(check_size, std::placeholders::_1, 6); // 占位符 _1 表示占住check_size的第一个参数的位置,之后传递给 _1 的参数,将作为check_size的第一个实参。

    find_if(v.begin(), v.end(), check6);

  • 50
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值