【C++11】lambda表达式、包装器、bind 与 placeholders

【C++11】包装器和bind arg_list中的参数可能包含形如_n的名字,其中n是⼀个整数,这些参数是占位符,表示newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第⼀个参数,_2为第二个参数,以此类推。函数指针、仿函数、 lambda 等可调用对象的类型各不相同, std::function 的优势就是统⼀类型,对他们都可以进行包装,这样在很多地方就方便声明可调用对象的类型。表达式中的占位符决定的,一般用auto接受。 阅读详情

目录

一、lambda表达式

1.1 lambda的产生

1.2 lambda 格式

1.3 lambda捕捉列表

1.4 函数对象与lambda表达式

二、包装器

2.1 包装器的引入

2.2 包装器的使用

2.3 包装器的运用

三、bind 绑定

3.1 bind的引入

3.2 bind 的使用


一、lambda表达式

1.1 lambda的产生

C++98中的一个例子

在C++98中,如果想对一个数据集合中的元素进行排序,可以使用 std::sort方法。

那如果待排序元素为自定义类型,需要用户定义排序时的比较规则,例如下面这个例子:

struct Goods
{
 string _name;  // 名字
 double _price; // 价格
 int _evaluate; // 评价
 Goods(const char* str, double price, int evaluate)
 :_name(str)
 , _price(price)
 , _evaluate(evaluate)
 {}
};

这有一个类Goods,如果我们想使用sort按名字进行升序、降序排序就需要写两个仿函数;如果想按价格进行排序,又要写两个仿函数,如果按评价排序,也是两个仿函数。

随着C++语法的发展,有人觉得这种写仿函数太复杂了,每次为了实现一个 algorithm算法,都要去重新写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,这都给编程带来了极大的不便。因此,C++11语法汇总出现了Lambda表达式解决这个问题。

1.2 lambda 格式

lambda表达式书写格式:

[capture-list] (parameters) mutable -> return-type {statement}

格式说明:

  • [capture-list]:捕捉列表。该列表总是出现在lambda函数的开始位置,编译器根据 [] 来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文种的变量供lambda函数使用。
  • (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略。
  • mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
  • ->returntype:返回值类型。用于追踪返回类型形式声明函数的返回值类型,没有返回值此部分可以省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
  • {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

注意:

在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体不能省略,但可以为空。因此C++11中最简单的lambda函数为:[ ] { };该lambda无法实现任何功能。

举例:

[ ](const Goods& g1, const Goods& g2) {return g1._evaluate > g2._evaluate; }

函数有4个部分组成:返回值,函数名,函数参数,函数体;而lambda没有函数名,多了一个捕捉列表。

可以看出 lambda 本质就是一个匿名函数。该函数无法直接被调用,如果想要直接调用,可借助 auto 将其赋值给一个变量。

使用:

1.3 lambda捕捉列表

捕捉列表描述了上下文中哪些数据可以被lambda使用,以及使用的方式传值还是传引用。

  • [ var ] :表示值传递方式捕捉 var。
  • [ = ]:表示值传递方式捕获所有父作用域中的变量(包括 this)。
  • [ &var ]:表示引用传递补做变量 var 。
  • [ & ]:表示引用传递捕捉所有父作用域中的变量(包括 this)。
  • [ this ]:表示值传递方式捕捉当前的 this 指针。

注意:

  1. 父作用域指包含 lambda 函数的语句块。
  2. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
    1. 比如[ =, &a, &b ]:以引用传递的方式捕捉变量 a 和 b ,值传递方式捕捉其他所有变量。
    2. [ & , a , this ] :值传递方式捕捉变量 a 和 this ,引用方式捕捉其他变量。
  3. 捕捉列表不允许变量重复传递,否则就会导致编译错误。
    1. 比如[ = , a ]:=以及以值传递的方式捕捉了所有变量,捕捉 a 重复
  4. 在块作用域以外的 lambda 函数捕捉列表必须为空。
  5. 在块作用域中的 lambda 函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都会导致编译错误。
  6. lambda表达式之间不能相互赋值,即使看起来类型相同。

多个捕捉项的例子:捕捉全部变量,a变量使用引用捕捉:

接下来我们使用lambda表达式实现两值交换。观察使用 mutable 和引用捕捉两者的区别:

a和b属于当前test函数的作用域,而创建lambda则是当前lambda表达式的作用域,故mutable只是改变了表达式作用域下的长常量属性。如果要使用mutable能改变作用域内的值,可以再采用引用传参的方式。

1.4 函数对象与lambda表达式

函数对象,又称为仿函数,既可以像函数一样使用的对象,就是累类中重载了operator()运算符的函数对象。

接下来我们来看一段代码,我们先是使用仿函数去调用,然后再使用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(10000, 2);
	// lamber
	auto r2 = [=](double monty, int year)->double {return monty * rate * year; };
}

然后我们观察其汇编代码,观察编译器是如何处理仿函数和lambda表达式的,重点观察红框内的部分,发现其规律:

横线上是仿函数调用的汇编代码,下面是调用lambda的汇编代码。

我们首先简单了解一下什么是UUID:UUID----通用唯一识别码(Universally Unique Identifier)

其实就是一串有唯一标识的字符串。

  • 因为本质lambda就是仿函数,为了表示唯一标识,所以被编译器就将lambda处理成了一个类,命名为 lambda + UUID这种形式的仿函数。
  • 当lambda被声明赋值给一个变量时,就相当于调用了lambda的构造函数。而当lambda被调用时,编译器就会去调用这个对象operator()。
  • 所谓的捕捉其实就是仿函数的传参。

所以,为什么lambda表达式之间不能相互赋值的原因大家应该就理解了。

但是可以赋值给相同类型的函数指针。

void (*PF)();
int main()
{
 auto f1 = []{cout << "hello world" << endl; };
 auto f2 = []{cout << "hello world" << endl; };
 //f1 = f2;   // 编译失败--->提示找不到operator=()
 // 允许使用一个lambda表达式拷贝构造一个新的副本
 auto f3(f2);
 f3();

 // 可以将lambda表达式赋值给相同类型的函数指针
 PF = f2;
 PF();
 return 0;
}

二、包装器

2.1 包装器的引入

function包装器也叫做适配器,C++中的function本质是一个类模板,也是一个包装器。

那么我们来看看,我们为什么需要function。如以下这个例子:

ret = func(x);

上面的func可能是什么呢?

func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能是lambda表达式对象?所以这些都是可调用的类型,如此丰富的类型,可能会导致模板的效率低下。

接下来是这段代码的示例:

double f(double i)
{
	return i / 2;
}
struct Functor
{
	double operator()(double d)
	{
		return d / 3;
	}
};

template<class F, class T>
T useF(F f, T x)
{
	static int count = 0;
	cout << "count:" << ++count << endl;
	cout << "count:" << &count << endl;
	return f(x);
}

int main()
{
	// 函数名              //会调用f函数
	cout << useF(f, 11.11) << endl; 
	// 函数对象            //会调用functor()函数
	cout << useF(Functor(), 11.11) << endl;
	// lamber表达式        //会调用lambda表达式
	cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;
	return 0;
}

main函数中三条语句都调用了useF函数,因为useF是模板参数,所以传入什么类型的就会调用该类型,因为模板的是使用时才实例化,所以这个useF函数被实例化了三份!

接下来我们运行改代码,如果是同一个函数,static count则会被累加到3,如果是实例化了三份函数,static count 每次都会是1。结果如下:

而包装器的第一个作用就是让这种情况下,该useF函数只实例化为1份。

2.2 包装器的使用

接下来看看包装器如何使用的:

std::function在头文件<functional>
// 类模板原型如下
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;

模板参数说明:

  • Ret: 被调用函数的返回类型
  • Args…:被调用函数的形参

然后我们对普通函数、仿函数、lambda表达式进行包装一下。

int f(int a, int b)
{
	return a + b;
}
struct Functor
{
public:
	int operator() (int a, int b)
	{
		return a + b;
	}
};

int main()
{
	// 函数名(函数指针)
	std::function<int(int, int)> func1 = f;
	cout << func1(1, 2) << endl;
	// 函数对象
	std::function<int(int, int)> func2 = Functor();
	cout << func2(1, 2) << endl;

	// lamber表达式
	std::function<int(int, int)> func3 = [](const int a, const int b)
	{return a + b; };
	cout << func3(1, 2) << endl;
    return 0;
}

除了可以包装普通函数、仿函数、lambda表达式,还可以包装类的静态成员函数和类的成员函数。

首先是类的静态成员函数,包装方式如下:

如果是非静态的成员函数:

因为public的静态成员函数是可以直接调用的,而非静态的成员函数我们要用对象去调用,则要使用取地址操作符(语法规定),三处不同之处均标注出来了:

OK,现在我们来解决上面一份函数实例化三份的问题:

首先对三个函数进行包装,然后传入包装后的函数,在模板参数看来,虽然f1、f2、f3函数实现不同,但是f1、f2、f3函数都是function<double(double)>类型,,所以该模板函数因为三次调用参数类型相同,则只会实例化为一份。

2.3 包装器的运用

有了这个包装器,我们可以在实际中便可以运用到,比如之前我博客上讲过的一道LeetCode经典题:150. 逆波兰表达式求值。

正常的写法可以看我往期的博客,讲解:leetcode150/155. 逆波兰表达式求值

这里我们是讲解使用包装器如何解决这道题。

思想:

        我们可以让将各种运算符进行的处理函数用lambda表达式实现,因为类型本质是相同的,我们使用包装器进行包装,让对应的运算符和对应的运算处理函数进行绑定一起放入到map中。

        我们遍历数组时,如果检测到了运算符,直接调用数据调用运算符对应的处理方式即可。

 这里再介绍以下map中的count接口,我们也可以在此进行使用.

因为我们将运算符都插入到Map中了,如果该操作符存在则返回1,不存在返回0。此接口也可以用于判断key在不在。其实用 find 一样可以达到该效果。

 全部代码如下:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long> st;
        map<string,function<long long(long long,long long )>> operaMap=
        {
            {"+",[](long long a,long long b){return a+b;}},
            {"-",[](long long a,long long b){return a-b;}},
            {"*",[](long long a,long long b){return a*b;}},
            {"/",[](long long a,long long b){return a/b;}}
        };

        for(auto& str:tokens)
        {
            //如果是运算符:
            //if(operaMap.find(str)!=operaMap.end())
            //map中的count接口,该key存在则返回1,不存在返回0,也可以用于判断key在不在
            if(operaMap.count(str))
            {
                long long right=st.top();
                st.pop();
                long long left=st.top();
                st.pop();
                //调用运算函数,
                long long temp=operaMap[str](left,right);
                //再将结果入栈
                st.push(temp);
            }
            //
            else 
            {
                st.push(stoll(str));
            }
        }
        return st.top();
    }
};

三、bind 绑定

3.1 bind的引入

现在我们有一个普通函数和成员函数有相同的参数、返回值,此时我们考虑用包装器进行包装。

当包装完普通函数后,我们想再包装成员函数时,包装的方式就不同了,因为包装类的成员函数时我们还要传入类名。

而 bind 绑定的作用就是可以帮我们调整这些参数的顺序和个数。

std::bind函数定义在头文件中,是一个函数模板,它就像一个和函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。

bind函数会返回一个可调用对象。

参数 Fn 表示待绑定的函数,Args是一个逗号分隔的参数列表,对应给定函数的参数。当我们调用bind的返回对象时,该返回值会调用 Fn函数,然后将参数列表中的参数传给 Fn 函数。

3.2 bind 的使用

bind调整参数顺序

接下来我演示一下bind的使用:

int sub(int a, int b)
{
	return a - b;
}

这里有一个函数 sub,正常我们传入实参x和y,进入sub函数对应的就是形参a和b;我们可以使用 bind 调整传入的顺序。 例如下图,

这个效果就是使用bind绑定了一个函数,然后调整了其函数参数的位置,即调整了函数的形参顺序,绑定方式如下:

        调整函数参数的顺序,就是调整函数内形参的顺序,但是函数外部是取不到形参的,我们就可以使用 placeholders 命名空间中的占位,让原本传到函数第一个形参上的实参,传到第二个形参上。

配合 bind 函数一起使用的占位符(在命名空间placeholders中)

这样,原本传入函数形参1的实参就传给了形参2,实参2就传给了形参1。

 除了可以使用包装器的类型进行接收,图方便的话这里也是可以使用auto的,效果一样。

更想了解bind和placeholders的使用可以参考其他文献,这里主要讲解使用:C++11 bind 和 placeholders 用法

bind 补齐参数个数

接下来回到上面未解决的问题:让类的成员函数和普通函数一样被包装。

bind除了使用placeholders占位调整参数顺序,还可以传入固定的参数进行参数的补齐。

回顾这个问题,无法包装不就是因为类的成员函数进行调用时要传入类的构造函数吗,而这个构造函数又是固定的,所以我们进行bind绑定,让其默认传入构造函数,这样我们调用该函数不就跟调用普通函数一样了吗

绑定方式如下:

 除了绑定这种固定传入构造函数的函数,普通函数我们也可以进行固定绑定:

不过这样的话,第三个参数就无法改变了,这里只是想介绍bind也可以在此场景使用。

到现在,普通函数和类的成员函数我们就都进行了包装,我们就可以使用map进行事件与处理函数的绑定了:

C++包装器实战:std::function与std::bind优化模板代码与回调设计 在C++编程中,可调用对象(Callable Objects)是函数式编程和泛型设计的核心概念,包括函数指针、函数对象和lambda表达式等。其多样化的类型虽然提供了灵活性,但也导致了模板代码膨胀和编译效率低下等问题。为了解决这一问题,C++标准库引入了包装器(Wrappers)机制,通过类型擦除(Type Erasure)技术,将不同类型的可调用实体统一为标准化接口。以std::function为例,它作为可调用对象的通用容器,能够存储、复制和调用任何符合签名要求的对象,从而显著减少模板实例化次数,优化编 阅读详情

相关推荐

C++函数对象、lambda、bind与function深度解析:从原理到高性能实战

在C++编程中,函数对象(Functor)和lambda表达式是现代泛型编程和函数式编程的核心基础。函数对象通过重载operator()实现,本质上是可调用对象,它允许携带状态并支持编译器内联优化,相比传统函数指针在STL算法中具有显著性能优势。lambda表达式作为语法糖,在C++11后提供了更简洁的匿名函数定义方式,其捕获列表机制允许精确控制外部变量访问,同时编译器会将其转换为匿名函数对象,实现高效内联。这些技术共同支撑了回调机制、异步任务处理和泛型算法等关键应用场景。本文结合施磊老师的C++进阶课程,

dbp5156的博客 494

C++ tips_9 placeholders用法

C++ tips_9 placeholders用法

qq_41336087的博客 1419

C++11 bind 和 placeholders 用法

bind 这个东西是很鸡肋的,因为已经有了 lambda 表达式了,但是在 C++ 11 中 lambda 无法处理类型多态,bind可以;lambda 也不支持移动语义,bind 可以。 可喜的是,C++14 已经解决了上述两个问题,所以 bind 也就可以丢弃了。 1、std::placeholders 占位符 std::placeholders 是 C++ 11 的新特性,它一般和 bind 一起用。placeholders 定义如下: namespace placeholders { exter

深入浅出讲透复杂深奥的问题 2332

深入C++:实践中带你看 std::bind 和 std::placeholders 的各场景用法

是一个命名空间,它包含了一组占位符对象。这些占位符对象用于指示std::bind函数对象的参数位置。占位符的形式为_1_2_3,依此类推,表示第一个、第二个、第三个参数,等等。它在使用std::bind时非常有用。std::bind用于创建一个新的函数对象,该对象将原始函数的一些参数固定,而其他参数仍然可以在调用时指定。提供了占位符,用于表示这些在调用时指定的参数位置。

bigchen 2648

从建模到调参:基于Simulink的两轮差速机器人轨迹跟踪PID控制全流程解析

本文详细解析了基于Simulink的两轮差速机器人轨迹跟踪PID控制全流程,涵盖运动学建模、仿真环境搭建、PID控制器设计与实现等关键环节。通过Simulink仿真和可视化调试技巧,帮助开发者掌握移动机器人运动控制的核心技术,提升轨迹跟踪精度与性能优化能力。

weixin_28717683的博客 243

COCO数据集缺失文件补全方法

本文代码是以目标检测(object detection)和实例分割(instance segmentation)任务的标签文件为例,即文件。其他任务的标签文件内容略有不同,但是图片来源表示字段完全相同,因此代码可通用。另外如果是非2017版本COCO应该也通用。msgspec是一个高性能的序列化和验证库,支持 JSON、MessagePack、YAML 和 TOML 等多种格式。高性能:在常见协议的编码/解码中表现出色,通常比其他库快10-80倍。零成本的模式验证。

qq_46396470的博客 1995

C++11的占位符std::placeholders

占位符std::placeholders

有风楠来的博客 2万+

Open3D:Win10 + VS2017配置Open3D(C++、python)

一、下载源码 地址:https://github.com/intel-isl/Open3D 1.1 克隆源码【笔者的源码路径为D:\Open3D\Open3D】 1.2 切换版本【笔者的版本为0.8.0】 1.3 更新子模块【用于获取第三方库!很重要!】 二、CMake编译 2.1 设置路径 【source code: D:\Open3D\Open3D;build binaries: D:\Open3D】 【笔者设置CMAKE/CMAKE_INSTALL_PREFIX的路径为D:/Open.

累了就要打游戏 1万+

C++入门学习:std::function,std::bind,std::placeholders

占位符的作用就是用来代表参数的,std::placeholders::_1表示的是std::bind得到的std::function对象被调用时,传入的第一个参数,而std::placeholders::_2则是第二个参数。此外,我们也可以在std::bind的时候不用std::placeholders::_x,而直接写成固定的值,这样子调用std::function存储的对象时,对应位置的参数将是固定值。它的最基本的作用是,简化调用的复杂程度,统一调用的方式。三.std::placeholders。

az44yao的专栏 393

LabVIEW QMH模板实战:从创建到错误处理的完整指南

本文提供LabVIEW QMH模板从创建到错误处理的完整实战指南。详细解析了队列消息处理器(QMH)作为LabVIEW核心设计模式如何实现任务解耦与异步通信,涵盖事件处理循环、消息处理循环的搭建、用户事件创建、队列引用管理、消息优先级控制以及健壮的错误处理机制,帮助开发者构建稳定、可维护的复杂应用程序。

white的博客 725

VESC电调高级调参指南:电机校准与性能优化实战解析

本文详细解析了VESC电调的高级调参方法,包括电机校准与性能优化实战技巧。从基础参数设置到高级机械参数优化,再到动态性能调优,提供了全面的调参指南。特别针对电机类型、功率设置、电池参数配置等关键环节给出实用建议,帮助用户充分发挥VESC电调的性能潜力。

weixin_30772105的博客 196

【C++中可调用对象和function】

该函数包装器模板能包装任何类型的可调用实体,如普通函数,函数对象,lamda表达式等。个人认为五种可调用对象中,函数和函数指针本质相同,而lambda表达式、bind对象及仿函数则异曲同工。bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址,这是因为对象的成员函数需要有this指针。预绑定的参数是以值传递的形式,不预绑定的参数要用std::placeholders(占位符)的形式占位,从_1开始,依次递增,是以引用传递的形式;function包装仿函数。

Pass-by 386

【华为OD技术面试真题 - 技术面】- 测试面试题(1)

专栏:华为OD面试真题精选 目录: 2024华为OD面试手撕代码真题目录以及八股文真题目录黑盒测试:白盒测试:基本功能验证:边界条件测试:空白输入测试:特殊字符和格式测试:响应时间测试:压力测试:针对在不同系统和设备上测试聊天窗口功能,以及网络正常的前置条件,我们可以增加以下测试用例:系统和设备:PC端测试:移动端测试:功能验证:前置条件:网络性能影响测试:Postman:SoapUI:JMeter:Rest-Assured:Tricentis Tosca:ReadyAPI:CI/CD工具集成:测试管理工

算法大师! 3690

C++11:lambda表达式,包装器

C++11:lambda表达式,包装器

2401_88433210的博客 1289

使用Python实现深度学习模型:智能极端天气事件预测

在本项目中,我们成功利用Python和Keras库构建了一个基于LSTM的极端天气预测模型。通过时间序列数据,模型能够识别天气趋势并预测未来的极端天气事件。尽管这是一个简化的示例,但它为实际应用中如何利用深度学习进行天气预测提供了一个很好的基础。随着更精确的数据和更多的特征信息,类似的模型可以进一步扩展到其他极端事件预测上,如风暴预警、气象灾害评估等。

Echo_Wish 730

Python爬虫实战:京东/淘宝商品价格与评论监控系统——从User-Agent伪装到编码陷阱的全面攻克

在电商数据驱动决策的今天,无论是个人消费者想抓住历史低价,还是市场分析师需要追踪竞品动态,抑或是算法交易员依赖实时价格信号,自动化的商品价格与评论监控系统都已成为不可或缺的工具。然而,电商平台的反爬虫策略日益严苛,字符编码的“暗坑”更是让初学者屡屡碰壁。本文将以京东(JD.com和淘宝(Taobao.com两大主流平台为目标,手把手带你构建一个稳定、高效的商品监控爬虫。User-Agent伪装——如何模拟真实浏览器行为,突破初级反爬。GBK/UTF-8编码混战。

2201_76125261的博客 75

C++11:包装器

本文介绍了C++标准库中的两个重要工具:std::function和std::bind。std::function是一个可调用对象包装器,可以统一存储函数指针、仿函数、lambda等不同类型的可调用对象,并演示了其在逆波兰表达式求值问题中的应用。std::bind是函数适配器,能够调整参数顺序和数量,通过占位符实现灵活的参数绑定。文章通过多个代码示例展示了如何使用这两个工具包装各种可调用对象,包括普通函数、成员函数、lambda表达式等,并演示了bind在固定参数场景下的实用价值。这些工具在C++函数式编程

分享C,C++,数据结构,Linux,算法内容 351

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【C++11】 包装器解析

但行好事,莫问前程

qq_42996461的博客 2135

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【C++】C++11新特性—可变参数模版、lambda、包装器

可变参数模板、lambda表达式、包装器等。在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

小羊的博客 2180

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C++11新特性(lambda,可变参数模板,包装器,bind)

这样看其实也能够很好理解lambda表达式,我们不是嫌弃仿函数自己手动封装类太麻烦了嘛,lambda表达式就是让编译器自动帮我们封装,我们只要把函数的具体实现传过去就可以了,不过lambda表达式的功能比仿函数还是要强大很多的,我们后面慢慢说先看看上面程序的运行结果lambda表达式会自动帮我们推导返回值的类型,所以我们没有在lambda表达式中加上返回值的类型,如果你非想要指定具体的返回值类型,使用表达式中 ->returntype参数。

m0_61350245的博客 515

《C++11:function和bind》

本文介绍了C++11中的function和bind两个重要特性。function是一个类模板,用于统一包装函数指针、仿函数、lambda等可调用对象,方便类型声明和使用。bind是一个函数模板,作为函数适配器可以调整参数个数和顺序。文章通过代码示例演示了function包装各类可调用对象的方法,包括普通函数、仿函数、lambda表达式以及类成员函数。最后以LeetCode逆波兰表达式题目为例,展示了使用function优化代码的可扩展性。bind和function结合使用可以大大提高C++代码的灵活性和复用

Poeir_的博客 694

【C++】C++11(右值引用/移动语义/lambda/可变模板参数/包装器)

C++11新特性摘要:C++11是继C++98/03后的重要更新,带来约140个新特性。主要改进包括:1) 统一的列表初始化语法,支持所有内置和自定义类型;2) 右值引用和移动语义,解决深拷贝效率问题;3) 自动类型推导(auto)和类型获取(decltype);4) lambda表达式简化匿名函数编写;5) 可变参数模板支持更灵活的泛型编程;6) 完美转发(std::forward)保持参数类型属性;7) 新增移动构造和移动赋值默认成员函数;8) 包装器(std::function)统一函数对象调用方式。

wefg1的博客 817

C++编程中Lambda表达式与std::bind的对比与选择

在C++编程中,函数对象和回调机制是实现灵活代码设计的基础概念。其核心原理是通过封装可调用单元,将行为参数化,从而提升代码的模块化和复用性。从技术价值看,现代C++强调零开销抽象和编译期优化,这直接影响了函数封装技术的选择。Lambda表达式作为C++11引入的语法糖,本质是编译器生成的匿名函数对象,其闭包类型对编译器完全可见,支持内联优化,实现了接近手写代码的性能。相比之下,std::bind作为通用的运行时绑定器,涉及类型擦除和参数转发,会引入额外的间接调用开销。在应用场景上,无论是STL算法中的谓词、

weixin_33906657的博客 313

C++11四大核心特性:lambda、bind、function与可变模板协同实战

C++11引入的lambda表达式、std::bind、std::function和可变参数模板,共同构成了现代C++工程化落地的底层支柱。它们分别解决即兴逻辑封装、参数预设、类型擦除与泛型复用等关键问题,其协同机制远超语法糖范畴——lambda生成闭包对象实现零开销抽象,std::bind依赖可变模板支持任意参数绑定,std::function通过小对象优化平衡性能与灵活性。在风控系统、异步任务、日志库等高频场景中,合理组合这四大特性可显著降低内存泄漏率、提升编译效率并保障线程安全。本文聚焦生产级实践,解

weixin_34075268的博客 475

C++ std::function:统一回调、lambda与仿函数的万能包装器

在C++编程中,回调机制是实现事件驱动、异步处理和策略模式的核心技术。传统函数指针虽然基础,但无法统一处理lambda表达式、成员函数和仿函数等多样化的可调用对象,导致代码冗余且耦合度高。std::function通过类型擦除技术,在运行时动态包装任意签名匹配的可调用实体,提供了统一的调用接口。这一机制极大地提升了代码的灵活性和模块化程度,尤其适用于构建事件系统、实现命令模式或管理异步任务队列等场景。作为C++11引入的关键组件,std::function与lambda表达式协同工作,已成为现代C++高阶编

weixin_30325487的博客 415

C++11四大核心特性:lambda、可变模板、std::function与bind深度解析

C++11引入的lambda表达式、可变参数模板、std::function和std::bind,共同构成了现代C++高阶抽象的基石。它们并非语法糖,而是编译期类型系统与运行时灵活性协同演化的结果:lambda本质是编译器生成的匿名类,实现零开销闭包;可变参数模板通过参数包展开支持完美转发与编译期泛型;std::function提供类型擦除的统一调用接口;std::bind则用于参数预绑定。这些特性在高频交易、AI框架、嵌入式事件驱动等对性能与抽象能力双敏感的场景中,显著提升代码表达力与执行效率。本文聚焦其

aofan9566的博客 390
上一篇: 【C++11】可变参数模板
下一篇: 【C++】异常
Brant_zero2022
博客等级 码龄5年 582粉丝 108原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Brant_zero2022

素材免费分享不求打赏,只求关注

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值