当前位置: 首页 > article >正文

Lambda表达式随记

学习链接

目录

  • 作用
  • 定义
    • [capture list] 捕获列表
    • (paramter) 参数列表
    • mutable 可变规格
    • throw() 异常说明
    • -> return-type 返回类型
    • {function statement} lambda函数体
  • Lambda表达式的优缺点
  • Lambda表达式工作原理
  • 适用场景
    • STL算法库
    • 短小不需要复用函数场景

作用

Lambda表达式:在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。

定义

[capture list] (paramter) mutable throw() -> return-type {function statement}

以上依次为 捕获列表、参数列表、可变规格、异常说明、返回类型、lambda函数体。下面依次进行说明与详解。

[capture list] 捕获列表

C++规范中也称为Lambda导入器。[ ]是Lambda的引出符,编译器是根据这个引出符来判断接下来的代码是否为Lambda表达式,捕获列表可以捕捉上下文中的变量以供Lambda函数使用。
捕获列表有以下这些常用形式:

  • []表示不捕获任何变量
  • [var]表示值传递方式捕获变量var
  • [&var]表示引用传递捕获变量var
int num = 100;
auto function1 = ([num]{
		std::cout << num << std::endl;
	}
);//Lambda函数定义
function1();//函数调用

auto function2 = ([&num]{
		std::cout << num << std::endl;
	}
);
function2();
  • [=]表示值传递方式捕获所有父作用域的变量(其中也包括this)
  • [&]表示引用传递方式捕获所有父作用域的变量(其中也包括this)
int index = 1;
int num = 100;
auto function1 = ([=]{
			std::cout << "index: "<< index << ", " 
                << "num: "<< num << std::endl;
	}
);
function1();
auto function2 = ([&]{
		num = 1000;
		index = 2;
			std::cout << "index: "<< index << ", " 
                << "num: "<< num << std::endl;
	}
);
function2();
  • [this]表示值传递方式捕捉当前的this指针
#include <iostream>
using namespace std;
 
class Lambda
{
public:
    void sayHello() {
        std::cout << "Hello" << std::endl;
    };
    void lambda() {
        auto function = [this]{ 
            this->sayHello(); 
        };
        function();
    }
};
int main()
{
    Lambda demo;
    demo.lambda();
}
  • [=, &] 拷贝与引用混合
    • [=, &a, &b]表示以引用传递的方式捕捉变量a和b,以值传递方式捕捉其它所有变量
    • [&, a, this]表示以值传递的方式捕捉变量a和this,引用传递方式捕捉其它所有变量
    • 要注意的是,捕捉列表不允许变量的重复捕捉,如:[=,a]这里已经以值传递方式捕捉了所有变量,但是重复捕捉a了,会报错的;[&,&this]这里&已经以引用传递方式捕捉了所有变量,再捕捉this也是一种重复。
int index = 1;
int num = 100;
auto function = ([=, &index, &num]{
		num = 1000;
		index = 2;
		std::cout << "index: "<< index << ", " 
            << "num: "<< num << std::endl;
	}
);
function();

(paramter) 参数列表

除了捕获列表之外,Lambda还可以接受输入参数。参数列表是可选的,并且在大多数方面类似于函数的参数列表。

int index = 1;
int num = 100;
auto function = ([=, &index, &num]{
		num = 1000;
		index = 2;
		std::cout << "index: "<< index << ", " 
            << "num: "<< num << std::endl;
	}
);
function();

mutable 可变规格

mutable关键字可以打破const类型的限制,使得const类型的方法也可以修改成员变量的值。
默认情况下Lambda函数总是一个const函数(在这里就是不能修改参数列表变量,因为参数列表的变量相当于Lambda表达式工作原理里的类成员变量),mutable可以取消其常量性。
但是在使用该修饰符时,参数列表不可省略(即使参数为空)。

#include <iostream>
using namespace std;
int main()
{
   int m = 0;
   int n = 0;
   [&, n] (int a) mutable { m = ++n + a; }(4);
   cout << m << endl << n << endl;
}

throw() 异常说明

你可以使用 throw() 异常规范来指示 Lambda 表达式不会引发任何异常。与普通函数一样,如果 Lambda 表达式声明 C4297 异常规范且 Lambda 体引发异常,Visual C++ 编译器将生成警告 throw() 。

int main() // C4297 expected 
{ 
 	[]() throw() { throw 5; }(); 
}

-> return-type 返回类型

声明lambda函数的返回类型。但是这部分一般直接省略,编译器通过lambda函数体可对返回类型进行推导,无需特意声明返回类型。

{function statement} lambda函数体

内容与普通函数一致,只不过除了像普通函数那样可以使用参数列表里的参数之外,还可以使用捕获列表中所捕获到的参数。且没有mutable可变规格修饰时,传入的参数均为const传入,无法修改。

Lambda表达式的优缺点

优点:可以直接在需要调用函数的位置定义短小精悍的函数,而不需要预先定义好函数;使用Lamdba表达式变得更加紧凑,结构层次更加明显、代码可读性更好;
缺点:Lamdba表达式语法比较灵活,增加了阅读代码的难度;对于函数复用无能为力。

Lambda表达式工作原理

编译器会把一个Lambda表达式生成一个匿名类的匿名对象,并在类中重载函数调用运算符,实现了一个operator()方法。

auto print = []{cout << "Hello World!" << endl; };
//相当于:
class print_class
{
public:
	void operator()(void) const
	{
		cout << "Hello World!" << endl;
	}
};
// 用构造的类创建对象,print此时就是一个函数对象
auto print = print_class();
//所以这也可以解释下面这段代码:
[&, n] (int a) mutable { m = ++n + a; }(4);
//这里的(4)其实就相当于调用了operator()重载函数而已

适用场景

STL算法库

//for_each应用实例:
int a[4] = {11, 2, 33, 4};
sort(a, a+4, [=](int x, int y) -> bool { return x%10 < y%10; } );
for_each(a, a+4, [=](int x) { cout << x << " ";} );

//find_if应用实例:
int x = 5;
int y = 10;
deque<int> coll = { 1, 3, 19, 5, 13, 7, 11, 2, 17 };
auto pos = find_if(coll.cbegin(), coll.cend(), [=](int i) {                 
    return i > x && i < y;
});

//remove_if应用实例:
std::vector<int> vec_data = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int x = 5;
vec_data.erase(std::remove_if(vec.date.begin(), vec_data.end(), [](int i) { 
    return n < x;}), vec_data.end());

std::for_each(vec.date.begin(), vec_data.end(), [](int i) { 
    std::cout << i << std::endl;});

短小不需要复用函数场景

//sort函数:
vector<int> testdata;
testdata.insert(testdata.begin(), data, data + 6);
sort(testdata.begin(), testdata.end(), [](int a, int b){ return a > b; });

//Lamdba表达式应用于函数指针与function:
#include <iostream>
#include <functional>
using namespace std;

int main(void)
{
    int x = 8, y = 9;
    auto add = [](int a, int b) { return a + b; };
    std::function<int(int, int)> Add = [=](int a, int b) { return a + b; };
    
    cout << "add: " << add(x, y) << endl;
    cout << "Add: " << Add(x, y) << endl;

    return 0;
}

//Lamdba表达式作为函数的入参
using FuncCallback = std::function<void(void)>;
void DataCallback(FuncCallback callback)
{
	std::cout << "Start FuncCallback!" << std::endl;
	callback();
	std::cout << "End FuncCallback!" << std::endl;
}
auto callback_handler = [&](){
	std::cout << "This is callback_handler";
};
DataCallback(callback_handler);

//Lamdba表达式在QT中的应用
QTimer *timer=new QTimer;
timer->start(1000);
QObject::connect(timer, &QTimer::timeout, [&](){
        qDebug() << "Lambda表达式";
});

QTimer::singleShot(2000,[](){
        qDebug() << __FUNCTION__ << "QTimer::singleShot with Lambda表达式。";
});

int a = 10;
QString str1 = "汉字博大精深";
connect(pBtn4, &QPushButton::clicked, [=](bool checked){
	qDebug() << a <<str1;
	qDebug() << checked;
	qDebug() << "Hua Windows Lambda Button";
});



http://www.kler.cn/a/430591.html

相关文章:

  • 机器学习之PCA降维
  • HTML-CSS(day01)
  • RabbitMQ工作模式(详解 工作模式:简单队列、工作队列、公平分发以及消息应答和消息持久化)
  • 决策树(理论知识3)
  • JS中若干相似特性的区别
  • springBoot Maven 剔除无用的jar引用
  • 多AI代理框架全面对比:AutoGen、LangGraph、CrewAI、Swarm、Magentic-One,选对你的AI超级助手!
  • 软件测试丨Appium 源码分析与定制
  • 网络编程(2)(对于UDP与TCP协议深层理解)
  • hhdb客户端介绍(10)
  • 实时数据开发|Flink状态类型
  • 【面试】Spirng的IOC启动流程
  • qmake 生成debug/qmake 生成release
  • Linux 常用命令大全:文件管理、系统信息、网络操作
  • 40分钟学 Go 语言高并发:服务监控与追踪
  • selenium:新窗口切换、关闭
  • 【优选算法篇】:揭开二分查找算法的神秘面纱--数据海洋中的精准定位器
  • 深入探索 JVM:原理、机制与实战
  • docker-compose 安装部署zabbix
  • 2024年发布的多模态大语言模型和它们采用的设计方法
  • RabbitMQ如何保证消息不被重复消费
  • zookeeper 搭建集群
  • 理解 CAP 理论:分布式系统中的权衡与选择 | 常用组件中的CP和AP
  • 48 基于单片机的LCD12864时间调控和串口抱站
  • 阿里云函数计算助力AI大模型快速部署
  • 孚盟云 MailAjax.ashx SQL注入漏洞复现