C/C++ Lambda表达式概述

基本概述:

关于Lambda表达式之前接触过,但是没有系统总结过,这里整一个基础版的总结;

关于lambda表达式,可以看作三种函数调用形式的最高级别;

之前接触过:函数指针、仿函数;

lambda可以看作仿函数的升级版;

例如其他blog举例:

class Plus {
 public:
  int operator()(int a, int b) {
    return a + b;
  }   
};

相比于函数指针,更容易在类内保留信息和状态,并且调用和函数类似,原因是重载了"()"操作符:

Plus plus; 
std::cout << plus(11, 22) << std::endl;   // 输出 33

对于lambda而言,可以看作仿函数的升级版本;

其实对于编译器的实现而言,其本质上也是隐式构造了一个函数体,例如:

auto plus = [] (int a, int b) -> int { return a + b; }
int c = plus(1, 2);

则编译器则会将表达式翻译为:

class LambdaClass
{
public:
    int operator () (int a, int b) const
    {
        return a + b;
    }
};

LambdaClass plus;
int c = plus(1, 2);

可以看到其实就是仿函数的一种特例而已;

基本形式:

lamda表达式具体形式如下所示:

[ capture-list ] ( params ) mutable(optional) exception(optional) attribute(optional) -> ret(optional) { body };

其中exception、attribute目前先不说,后续遇到在补充;

其中ret为指定的返回形式,这里通常可以省略;

capture-list:

捕获列表主要讲述内部所需要的值是如何捕获的;

[] 什么也不捕获,无法lambda函数体使用任何

[=] 按值的方式捕获所有变量

[&] 按引用的方式捕获所有变量

[=, &a] 除了变量a之外,按值的方式捕获所有局部变量,变量a使用引用的方式来捕获。这里可以按引用捕获多个,例如 [=, &a, &b,&c]。这里注意,如果前面加了=,后面加的具体的参数必须以引用的方式来捕获,否则会报错。

[&, a] 除了变量a之外,按引用的方式捕获所有局部变量,变量a使用值的方式来捕获。这里后面的参数也可以多个,例如 [&, a, b, c]。这里注意,如果前面加了&,后面加的具体的参数必须以值的方式来捕获。

[a, &b] 以值的方式捕获a,引用的方式捕获b,也可以捕获多个。

[this] 在成员函数中,也可以直接捕获this指针,其实在成员函数中,[=]和[&]也会捕获this指针。

其中,也可以给捕获的值进行列表初始化,即进行重命名;
例如:

// 按值捕获 target,但是在 Lambda 内部的变量名叫做 v
auto cnt =
    std::count_if(books.begin(), books.end(), [v = target](const Book& book) {
        return book.title.find(v) != std::string::npos;
    }); 

// 按引用捕获 target,但是在 Lambda 内部的名字叫做 r
auto cnt =
    std::count_if(books.begin(), books.end(), [&r = target](const Book& book) {
        return book.title.find(r) != std::string::npos;
    }); 

也可以进行右值捕获,用于捕获“Move-only”对象,原因是"Move-only"对象无法进行引用或者复制捕获:

std::unique_ptr<int> uptr = std::make_unique<int>(123);
auto callback = [&uptr]() {                               
    std::cout << *uptr << std::endl;
};  

也可以进行指针捕获:

auto cnt =
    std::count_if(books.begin(), books.end(), [p = &target](const Book& book) {
        return book.title.find(*p) != std::string::npos;
    }); 

表达式主体以及形式:

表达式主体可以直接按照函数形式进行书写,但是要注意一下啊值捕获的问题;

值捕获生成的类形式为:

auto plus = [=] (int a, int b) -> int { return x + y + a + b; };
//翻译为:
class LambdaClass
{
public:
    LambdaClass(int xx, int yy)
    : x(xx), y(yy) {}

    int operator () (int a, int b) const
    {
        return x + y + a + b;
    }

private:
    int x;
    int y;
}

int x = 1; int y = 2;
LambdaClass plus(x, y);
int c = plus(1, 2);

其中可以看到,符号运算函数为const函数,标志无法在内部进行值修改;

并且值得注意的是,捕获的值作为成员,私有持有,并且传入参数为运算符重载传入的参数;

为了避免这种情况,可以加上mutable关键字;

auto plus = [=] (int a, int b) mutable -> int { x++; return x + y + a + b; };

相应的,对于引用捕获,可以翻译为:

auto plus = [&] (int a, int b) -> int { x++; return x + y + a + b;};
//翻译形式为:
class LambdaClass
{
public:
    LambdaClass(int& xx, int& yy)
    : x(xx), y(yy) {}

    int operator () (int a, int b)
    {
        x++;
        return x + y + a + b;
    }

private:
    int &x;
    int &y;
};
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值