【C++ 学习 ㉛】

编程入门 行业动态 更新时间:2024-10-15 04:27:28

【C++ 学习 ㉛】

【C++ 学习 ㉛】

目录

一、语法格式

二、函数对象和 lambda 表达式


 


一、语法格式

定义一个 lambda 表达式(lambda 函数)的语法格式如下:

[capture-list] (parameters) mutable noexcept/throw() -> return-type { statements };
即
[捕获列表] (参数列表) 可变规则 异常说明 -> 返回类型 { 函数体 };

其中各部分的含义分别为:

  1. [捕获列表]:[] 是 lambda 引出符,编译器根据该引出符判断接下来的代码是否为 lambda 函数,所以其不能被省略。捕获列表能够捕获外部变量(即和当前 lambda 函数位于同一作用域内的所有局部变量)以供 lambda 函数使用

    捕获列表可由多个捕获项组成,并以逗号分割。捕获列表有以下几种形式

    [捕获列表]说明
    []不捕获任何外部变量
    [=]以值传递的方式捕获所有外部变量(包括 this)
    [&]以引用传递的方式捕获所有外部变量(包括 this)
    [val1, val2, ...]以值传递的方式捕获 val1、val2 等指定的外部变量
    [&val1, &val2, ...]以引用传递的方式捕获 val1、val2 等指定的外部变量
    [=, &val1, ...]以引用传递的方式捕获 val1 等指定的外部变量,以值传递的方式捕获其他所有外部变量
    [&, val1, ...]以值传递的方式捕获 val1 等指定的外部变量,以引用传递的方式捕获其他所有外部变量
    [this]以值传递的方式捕获当前的 this 指针

    注意:捕获列表不允许外部变量重复传递,例如 [=, val1]、[&、&val1]

  2. (参数列表):和普通函数不同的是,如果不需要传递参数,可以连同 () 一起省略

  3. 可变规则:mutable 关键字可以省略,如果要使用,则之前的 () 将不能省略(参数个数可以为 0)。默认情况下,以值传递方式捕获的外部变量,不允许在 lambda 函数内部修改它们的值(可以理解为这部分变量都是 const 变量),如果想修改它们,就必须使用 mutable 关键字

    注意:修改以值传递方式捕获的外部变量,实则修改的是外部变量的拷贝,而不是真正的外部变量

  4. 异常说明:可以省略,如果要使用,则之前的 () 将不能省略(参数个数可以为 0)。默认情况下,lambda 函数的函数体中可以抛出任何类型的异常,标注 noexcept 关键字,则表示函数体内不会抛出任何异常;使用 throw() 则可以指定 lambda 函数内部可以抛出的异常类型

  5. -> 返回类型:返回类型为 void,可以省略;返回类型明确的情况下,也可以省略,由编译器对返回类型进行推导

  6. { 函数体 }:函数体内部除了可以使用指定传递进来的参数,还可以使用所有捕获的外部变量以及全局范围内的所有全局变量

示例一

#include <iostream>
using namespace std;
​
class A
{
public:A(int x = 0) : _i(x) { }
​void sayHello() const { cout << "Hello" << endl; }
​void test(){// 以值传递的方式捕获当前的 this 指针auto func = [this] {this->_i = 10;cout << this->_i << endl;this->sayHello();// 函数体中 this 可以省略};func();}
private:int _i;
};
​
int main()
{// 最简单的 lambda 表达式,该表达式没有任何意义[] {};
​A a;a.test();// 10// Helloreturn 0;
}

示例二

#include <string>
#include <vector>
#include <algorithm>
using namespace std;
​
// 商品类
struct Goods
{string _name;  // 名字double _price;  // 价格int _eval;  // 评价
​Goods(const char* str, double price, int eval): _name(str), _price(price), _eval(eval){ }
};
​
struct CmpByPriceLess
{bool operator()(const Goods& lhs, const Goods& rhs){return lhs._price < rhs._price;}
};
​
struct CmpByPriceGreater
{bool operator()(const Goods& lhs, const Goods& rhs){return lhs._price > rhs._price;}
};
​
int main()
{vector<Goods> v = {{ "苹果", 2.1, 5 },{ "香蕉", 3.0, 4 },{ "橙子", 2.2, 3 },{ "菠萝", 1.5, 4}};
​// 按价格排序方法一:sort(v.begin(), v.end(), CmpByPriceLess());  // 升序sort(v.begin(), v.end(), CmpByPriceGreater());  // 降序
​// 按价格排序方法二:sort(v.begin(), v.end(), [](const Goods& lhs, const Goods& rhs) {return lhs._price < rhs._price; });  // 升序sort(v.begin(), v.end(), [](const Goods& lhs, const Goods& rhs) {return lhs._price > rhs._price; });  // 降序return 0;
}


二、函数对象和 lambda 表达式

// 利率类
class Rate
{
public:Rate(double rate) : _rate(rate) { }
​double operator()(double money, int year){return money * _rate * year;  // 利息 = 本金 * 利率 * 存期}
private:double _rate;
};
​
int main()
{double rate = 0.49;// 函数对象Rate r1(rate);  r1(1000, 2);
​// lambda 表达式auto r2 = [rate](double money, int year) {return money * rate * year;}; r2(1000, 2);return 0;
}

所以实际上在底层中,编译器对一个 lambda 表达式的处理方式,完全就是按照函数对象的方式来处理的,即如果定义了一个 lambda 表达式,编译器会自动生成一个类,该类中重载了 operator()

注意:lambda 表达式即使看起来是一样,但它们的类型实际上是不相同的

#include <iostream>
using namespace std;
​
int main()
{auto add1 = [](int x, int y) { return x + y; };auto add2 = [](int x, int y) { return x + y; };cout << typeid(add1).name() << endl;// class <lambda_2af21e002ff22901d6b0fa11901f235e>cout << typeid(add2).name() << endl;// class <lambda_751ae2273733b2c2d261a415ac8d186d>return 0;
}

更多推荐

【C++ 学习 ㉛】

本文发布于:2023-11-16 20:44:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1634047.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!