C++ 匿名函数

匿名函数,顾名思义就是没有名字的函数,又名Lambda。
为什么使用匿名函数,优点如下

  1. 使用匿名函数,可以免去函数的声明和定义。这样匿名函数仅在调用函数的时候才会创建函数对象,而调用结束后立即释放,所以匿名函数比非匿名函数更节省空间
  2. 不希望被其他人广泛地调用,只是为了在自己的局部代码中理顺逻辑和减少重复
  3. Lambda 表达式可以减少程序中函数对象类的数量,使得程序更加优雅
  4. 匿名函数是我们需要用到的一个函数,但是又不想去费力命名一个函数的场景。我们无需为每个值或者每种类型)单独编写函数,更不必把值保存在让人厌倦的全局变量中
匿名函数结构
[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 {
// 函数体
}

e.g.
auto f = [] (int x, int y) mutable throw -> int {return a + b;}

// 省略不必要的
[]() {
	std::cout << "Lambda" << std::endl;
}()
  • 捕获列表,指明定义环境中的那些名字能被用在lambda表达式内,以及这些名字的访问形式拷贝还是引用,捕获列表位于 [] 内,可以为空
  • 参数列表
  • mutable, 当捕获列表以值的方式传递后,lambda表示不能修改这个变量的值,只能使用; 不加mutable, 无法修改按值传入的副本。mutable类似于对按值捕获的变量进行去const操作,不会影响外部的值, 可省略
  • 异常属性, Lambda表达式可以抛出指定类型的异常; 可省略
  • ->返回类型,可省略
捕获列表
  1. []:默认不捕获任何变量;
  2. [=]:默认以值捕获所有变量;
  3. 注意:默认值捕获,在成员函数内,会默认按值捕获this指针,但因为this指针指向的是某个指向调用当前成员函数的对象,所以其实是已经获取了修改成员变量的所有权。
  4. [&]:默认以引用捕获所有变量;注意的是:引用捕获不会延长变量的生命周期;
  5. [x, y]:仅以值捕获x, y,其它变量不捕获;
  6. [&x]:仅以引用捕获x,其它变量不捕获;
  7. [=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获;
  8. [&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获;
  9. [this]:通过引用捕获当前对象(其实是复制指针);对成员函数来说,[this] [=],可以进行成员变量的操作
  10. [*this]:通过传值方式捕获当前对象;
捕获分析

值捕获与参数传值类似,值捕获的前提是变量可以拷贝,不同之处则在于,被捕获的变量在 lambda 表达式被创建时拷贝, 而非调用时才拷贝

#include 
void value_capture() {
    int value = 1;
    auto copy_value = [value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
}


int main(int argc,char ** argv)
{
  value_capture();
}
// 这时, stored_value == 1, 而 value == 100.
// 因为 copy_value 在创建时就保存了一份 value 的拷贝

引用捕获与引用传参类似,引用捕获保存的是引用,值会发生变化:

void reference_capture() {
    int value = 1;
    auto copy_value = [&value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 100, value == 100.
    // 因为 copy_value 保存的是引用
}
lambda表达式返回值

在使用lambda表达式时,有时候可以不用指定放回类型,但有时必须指定返回类型,否者将会出错。
一般情况下,编译器会自动推断出lambda的返回类型但是如果函数体里面有多个返回语句,甚至有一些常量return返回时候,编译器无法自动推断其返回类型,这个时候我们需要指定其返回类型

auto func_1=[] (int I) {return I;};   //编译器推断返回类型为int型
auto func_2=[] (int I) {cout<<I<<endl;};   //编译器推断返回类型为void型,也就是lambda不返回任

auto func_3=[] (int I) { if(I<0) return 0;else return 1;};   //虽然两个return语句都返回int型,但编译器不能推断出其返回类型,所以该语句会产生编译错误。
auto func_3=[] (int I) -> int {if (I<0) return 0; else return 1;};  //指定返回类型必须采用尾置返回类型(即-> type的形式) 
参考文章

[1] C++的匿名函数(lambda表达式)
[2] C++11 Lambda表达式(匿名函数)详解
[3] 搞懂C++11中的匿名函数 | 第93期
[4] C++ 匿名函数
[5] C++新特性12_ Lambda

你可能感兴趣的:(C++/C,c++)