首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C++11】lambda和包装器

【C++11】lambda和包装器

作者头像
Ronin305
发布2025-12-22 12:34:10
发布2025-12-22 12:34:10
1880
举报
文章被收录于专栏:我的博客我的博客

1. Lambda 表达式

1.1 Lambda 表达式语法

  • Lambda 表达式本质上是一个匿名函数对象,与普通函数不同之处在于它可以定义在函数内部
  • 从语法层面看,Lambda 表达式没有显式类型,因此通常使用 auto 或模板参数来接收 Lambda 对象

Lambda 表达式的基本格式:

代码语言:javascript
复制
[capture-list] (parameters)-> return-type { function-body }

各组成部分说明:

  1. [capture-list]: 捕捉列表
    • 必须出现在 Lambda 函数的开头位置
    • 编译器通过 [] 来判断是否为 Lambda 函数
    • 用于捕捉上下文中的变量(可传值或传引用,详见 1.2 节)
    • 即使为空也不能省略
  2. (parameters):参数列表
    • 功能与普通函数相同
    • 若无参数可连同括号一起省略
  3. ->return-type:返回值类型
    • 采用追踪返回类型形式声明
    • 无返回值时可省略
    • 当返回值类型明确时,通常可省略并由编译器推导
  4. {function-body}:函数体
    • 实现方式与普通函数类似
    • 可使用参数和所有捕获的变量
    • 即使为空也不能省略

下面我们通过代码来看看lambda是怎么用的

代码语言:javascript
复制
int main()
{
	// 一个简单的lambda表达式
	auto add1 = [](int x, int y)->int {return x + y; };
	cout << add1(1, 2) << endl;
	// 1、捕捉为空也不能省略
	// 2、参数为空可以省略
	// 3、返回值可以省略,可以通过返回对象自动推导
	// 4、函数体不能省略
	auto func1 = []
		{
			cout << "hello bit" << endl;
			return 0;
		};
	func1();
	int a = 0, b = 1;
	auto swap1 = [](int& x, int& y)
		{
			int tmp = x;
			x = y;
			y = tmp;
		};
	swap1(a, b);
	cout << a << ":" << b << endl;
	return 0;
}

运行结果:


1.2 捕获列表

• lambda 表达式默认只能访问函数体和参数中的变量,如需使用外层作用域的变量,需通过捕获列表实现

• 显式捕获方式分为值捕获和引用捕获,多个捕获变量用逗号分隔。例如:[x, y, &z] 表示对x和y进行值捕获,对z进行引用捕获

• 隐式捕获方式通过在捕获列表中使用符号自动捕获变量:

  • "=" 表示对所有使用变量进行值捕获
  • "&" 表示对所有使用变量进行引用捕获

• 混合捕获方式允许同时使用显式和隐式捕获:

  • [=, &x] 表示其他变量值捕获,x引用捕获
  • [&, x, y] 表示其他变量引用捕获,x和y值捕获
  • 混合捕获时,第一个元素必须是"&"或"=",且后续捕获类型需与之相反

• 局部作用域中的lambda表达式:

  • 只能捕获其定义位置之前的变量
  • 不能捕获静态局部变量和全局变量(这些变量可直接使用)
  • 全局定义的lambda表达式捕获列表必须为空

• 捕获变量默认具有const属性:

  • 值捕获的变量不可修改
  • 使用mutable修饰符可取消const属性(此时参数列表不可省略)
  • 修改仅作用于形参,不影响实参

通过下面代码来了解一下捕获列表的作用

代码语言:javascript
复制
int x = 0;
// 捕捉列表必须为空,因为全局变量不用捕捉就可以用,没有可被捕捉的变量
auto func1 = []()
{
	x++;
};
int main()
{
	// 只能用当前lambda局部域和捕捉的对象和全局对象
	int a = 0, b = 1, c = 2, d = 3;
	auto func1 = [a, &b]
	{
		// 值捕捉的变量不能修改,引用捕捉的变量可以修改
		//a++; // 错误,不能修改
		b++;
		int ret = a + b;
		return ret;
	};
	cout << func1() << endl;
	// 隐式值捕捉
	// 用了哪些变量就捕捉哪些变量
	auto func2 = [=]
	{
		int ret = a + b + c;
		return ret;
	};
	cout << func2() << endl;
	// 隐式引用捕捉
	// 用了哪些变量就捕捉哪些变量
	auto func3 = [&]
	{
		a++;
		c++;
		d++;
	};
	func3();
	cout << a << " " << b << " " << c << " " << d << endl;
	// 混合捕捉1
	auto func4 = [&, a, b]
	{
		//a++;
		//b++;
		c++;
		d++;
		return a + b + c + d;
	};
	func4();
	cout << a << " " << b << " " << c << " " << d << endl;
	// 混合捕捉1
	auto func5 = [=, &a, &b]
	{
		a++;
		b++;
		/*c++;
		d++;*/
		return a + b + c + d;
	};
	func5();
	cout << a << " " << b << " " << c << " " << d << endl;
	// 局部的静态和全局变量不能捕捉,也不需要捕捉
	static int m = 0;
	auto func6 = []
	{
		int ret = x + m;
		return ret;
	};
	// 传值捕捉本质是一种拷⻉,并且被const修饰了
	// mutable相当于去掉const属性,可以修改了
	// 但是修改了不会影响外面被捕捉的值,因为是一种拷⻉
	auto func7 = [=]()mutable
	{
		a++;
		b++;
		c++;
		d++;
		return a + b + c + d;
	};
	cout << func7() << endl;
	cout << a << " " << b << " " << c << " " << d << endl;
	return 0;
}

运行结果:


1.3 Lambda 表达式的应用:现代 C++ 的简洁之道

在 C++11 引入 lambda 表达式之前,开发者主要依靠函数指针仿函数(函数对象) 来实现可调用行为。这两种传统方式各有其局限性,而 lambda 表达式则提供了一种革命性的替代方案,极大地简化了代码并提升了开发效率。

一、传统可调用对象的痛点
1. 函数指针的繁琐性
代码语言:javascript
复制
// 1. 定义函数原型
void process_element(int value, double factor);

// 2. 定义函数实现
void process_element(int value, double factor) {
    std::cout << value * factor;
}

// 3. 使用函数指针
void (*func_ptr)(int, double) = &process_element;
func_ptr(10, 2.5);  // 调用

问题

  • 需要单独定义函数,破坏代码局部性
  • 类型签名复杂,可读性差
  • 无法捕获上下文状态
2. 仿函数的实现复杂度
代码语言:javascript
复制
// 1. 定义完整的类
class Multiplier {
    double factor_;
public:
    Multiplier(double factor) : factor_(factor) {}
    
    // 2. 重载函数调用运算符
    void operator()(int value) const {
        std::cout << value * factor_;
    }
};

// 3. 使用仿函数
Multiplier multiplier(2.5);
multiplier(10);  // 调用

问题

  • 需要定义完整的类结构
  • 代码分散,逻辑不够集中
  • 简单功能也需要大量样板代码
二、Lambda 表达式的简洁优势
1. 就地定义,保持代码连贯性
代码语言:javascript
复制
// 直接在调用点定义逻辑
auto process = [factor = 2.5](int value) {
    std::cout << value * factor;
};

process(10);  // 调用

优势

  • 逻辑与使用点紧邻,提高可读性
  • 无需预先定义函数或类
  • 减少代码文件间的跳转
2. 自动类型推导
代码语言:javascript
复制
// 编译器自动推导返回类型
auto square = [](auto x) { return x * x; };

// 支持多种类型
std::cout << square(5);    // int: 25
std::cout << square(2.5);  // double: 6.25
3. 闭包捕获上下文
代码语言:javascript
复制
int base = 100;
double factor = 1.5;

// 捕获局部变量
auto calculator = [base, &factor](int value) {
    factor += 0.1;  // 修改引用捕获的变量
    return (base + value) * factor;
};

std::cout << calculator(50);  // (100+50)*1.6 = 240
三、Lambda 在实际开发中的典型应用
1. 多线程编程
代码语言:javascript
复制
// 创建线程并定义执行逻辑
std::thread worker([task_id = 42] {
    std::cout << "Starting task " << task_id << "\n";
    perform_computation();
    std::cout << "Completed task " << task_id << "\n";
});

worker.join();

优势

  • 直接捕获任务相关参数
  • 逻辑封装在任务启动点
  • 避免定义额外函数
2. 智能指针自定义删除器
代码语言:javascript
复制
// 文件资源管理
auto file_deleter = [](FILE* f) { 
    if (f) {
        std::cout << "Closing file\n";
        fclose(f);
    }
};

// 使用lambda作为删除器
std::unique_ptr<FILE, decltype(file_deleter)> 
    file_ptr(fopen("data.txt", "r"), file_deleter);

对比传统方式

代码语言:javascript
复制
// 传统函数指针方式
void file_deleter_func(FILE* f) { /*...*/ }
std::unique_ptr<FILE, void(*)(FILE*)> 
    ptr(fopen(...), &file_deleter_func);
3. STL 算法定制
代码语言:javascript
复制
std::vector<Person> people;

// 按年龄排序
std::sort(people.begin(), people.end(), 
    [](const Person& a, const Person& b) {
        return a.age < b.age;
    });

// 查找特定条件的人
auto it = std::find_if(people.begin(), people.end(),
    [](const Person& p) {
        return p.name.starts_with("A") && p.age > 30;
    });
4. 异步任务封装
代码语言:javascript
复制
// 提交异步任务
auto future = std::async(std::launch::async, 
    [url = "https://example.com"] {
        return fetch_data(url);  // 捕获URL
    });

// 获取结果
auto result = future.get();
5. GUI 事件处理
代码语言:javascript
复制
// 按钮点击事件处理
button.on_click([&counter, this](const Event& e) {
    counter++;  // 捕获计数器引用
    update_display();  // 捕获this指针
    log_event(e);      // 访问事件对象
});
6. 回调函数简化
代码语言:javascript
复制
// 传统C风格回调
void register_callback(void (*callback)(int, void*), void* data);

// 使用lambda封装状态
int state = 42;
register_callback([](int result, void* data) {
    int* s = static_cast<int*>(data);
    std::cout << "Result: " << result << ", State: " << *s;
}, &state);

// C++11后更优雅的方式
std::function<void(int)> callback = [&state](int result) {
    std::cout << "Result: " << result << ", State: " << state;
};
register_cpp_callback(callback);

1.4 lambda原理

• lambda的实现机制与范围for循环类似,从汇编指令层面来看,lambda和范围for都不存在实际指令。范围for底层通过迭代器实现,而lambda则通过仿函数对象实现。当我们编写一个lambda表达式时,编译器会自动生成对应的仿函数类。

• 编译器按照特定规则生成仿函数类名,确保每个lambda表达式对应唯一类名。lambda的参数、返回类型和函数体分别对应仿函数operator()的参数、返回类型和函数体实现。捕获列表中的变量会转化为仿函数类的成员变量,这些变量实际上是lambda类构造函数的参数。对于隐式捕获的情况,编译器会自动分析并传递实际使用的对象。

• 上述实现原理可以通过分析汇编代码来验证,后文展示的第二段汇编代码将证实这一机制的实现细节。

如下代码所示:

代码语言:javascript
复制
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;
	// lambda
	auto r2 = [rate](double money, int year) 
	{
		return money * rate * year;
	};
	// 函数对象
	Rate r1(rate);
	r1(10000, 2);
	r2(10000, 2);
	return 0;
}

在汇编代码中:

代码语言:javascript
复制
// lambda
auto r2 = [rate](double money, int year) 
{
	return money * rate * year;
};
// 捕捉列表的rate,可以看到作为lambda_1类构造函数的参数传递了,这样要拿去初始化成员变量
// 下面operator()中才能使用
00D8295C lea eax, [rate]
00D8295F push eax
00D82960 lea ecx, [r2]
00D82963 call `main'::`2': : <lambda_1>::<lambda_1> (0D81F80h)
			// 函数对象
			Rate r1(rate);
00D82968 sub esp, 8
00D8296B movsd xmm0, mmword ptr[rate]
00D82970 movsd mmword ptr[esp], xmm0
00D82975 lea ecx, [r1]
00D82978 call Rate::Rate(0D81438h)
			r1(10000, 2);
00D8297D push 2
00D8297F sub esp, 8
00D82982 movsd xmm0, mmword ptr[__real@40c3880000000000(0D89B50h)]
00D8298A movsd mmword ptr[esp], xmm0
00D8298F lea ecx, [r1]
00D82992 call Rate::operator() (0D81212h)
// 汇编层可以看到r2 lambda对象调用本质还是调用operator(),类型是lambda_1,这个类型名
// 的规则是编译器自己定制的,保证不同的lambda不冲突
			r2(10000, 2);
00D82999 push 2
00D8299B sub esp, 8
00D8299E movsd xmm0, mmword ptr[__real@40c3880000000000(0D89B50h)]
00D829A6 movsd mmword ptr[esp], xmm0
00D829AB lea ecx, [r2]
00D829AE call `main'::`2': : <lambda_1>::operator() (0D824C0h)
1. 编译器视角

Lambda 表达式会被转换为匿名函数对象:

代码语言:javascript
复制
// 原始lambda
auto lambda = [](int x) { return x * 2; };

// 编译器生成的等价类
class __AnonymousLambda {
public:
    auto operator()(int x) const {
        return x * 2;
    }
};
2. 捕获变量处理
代码语言:javascript
复制
int base = 100;

// 值捕获
auto add_val = [base](int x) { return x + base; };
/* 等价类 */
class __AddValLambda {
    int base;  // 值捕获的副本
public:
    __AddValLambda(int b) : base(b) {}
    auto operator()(int x) const { return x + base; }
};

// 引用捕获
auto add_ref = [&base](int x) { return x + base; };
/* 等价类 */
class __AddRefLambda {
    int& base;  // 引用捕获
public:
    __AddRefLambda(int& b) : base(b) {}
    auto operator()(int x) const { return x + base; }
};

2. 包装器

2.1 function 模板类

代码语言:javascript
复制
template <class T>
class function; // 未定义的通用模板

template <class Ret, class... Args>
class function<Ret(Args...)>; // 特化版本

std::function 是一个通用的函数包装器模板类,属于C++11标准库的一部分。它提供了一种类型安全的方式来存储、复制和调用各种可调用对象(callable objects)。

基本特性

包装能力:可以包装存储以下类型的可调用对象:

  • 函数指针(如 int(*)(int, int)
  • 成员函数指针(需配合std::bind使用)
  • 仿函数(重载了operator()的类对象)
  • lambda表达式
  • std::bind表达式
  • 其他std::function对象

状态检测

  • 当std::function不包含任何可调用对象时,称为"空"状态
  • 可以通过operator bool()或empty()方法检查是否为空
  • 调用空的std::function会抛出std::bad_function_call异常

头文件

代码语言:javascript
复制
#include <functional>
使用示例
  • 基本用法:
代码语言:javascript
复制
std::function<int(int, int)> func; // 声明一个接受两个int参数,返回int的function对象
func = [](int a, int b){ return a + b; }; // 包装lambda表达式
int result = func(2, 3); // 调用存储的可调用对象
  • 作为容器元素(实现命令模式示例):
代码语言:javascript
复制
std::map<std::string, std::function<void()>> command_map;
command_map["start"] = [](){ std::cout << "Starting...\n"; };
command_map["stop"] = [](){ std::cout << "Stopping...\n"; };

std::string cmd = "start";
if(command_map.find(cmd) != command_map.end()) {
    command_map[cmd](); // 调用对应的函数
}
性能特点
  • 存储的可调用对象会被复制到std::function内部
  • 对于小型可调用对象(如lambda),通常存储在内部缓冲区中
  • 对于大型可调用对象,可能会进行堆分配
  • 调用开销略高于直接调用原始可调用对象

参考文档: std::function - cppreference.com

代码语言:javascript
复制
int f(int a, int b)
{
	return a + b;
}
struct Functor
{
public:
	int operator() (int a, int b)
	{
		return a + b;
	}
};
class Plus
{
public:
	Plus(int n = 10)
		:_n(n)
	{}
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return (a + b) * _n;
	}
private:
	int _n;
};
int main()
{
	// 包装各种可调用对象
	function<int(int, int)> f1 = f;
	function<int(int, int)> f2 = Functor();
	function<int(int, int)> f3 = [](int a, int b) {return a + b; };
	cout << f1(1, 1) << endl;
	cout << f2(1, 1) << endl;
	cout << f3(1, 1) << endl;
	// 包装静态成员函数
	// 成员函数要指定类域并且前面加&才能获取地址
	function<int(int, int)> f4 = &Plus::plusi;
	cout << f4(1, 1) << endl;
	// 包装普通成员函数
	// 普通成员函数还有一个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以
	function<double(Plus*, double, double)> f5 = &Plus::plusd;
	Plus pd;
	cout << f5(&pd, 1.1, 1.1) << endl;
	function<double(Plus, double, double)> f6 = &Plus::plusd;
	cout << f6(pd, 1.1, 1.1) << endl;
	cout << f6(Plus(), 1.1, 1.1) << endl;
	function<double(Plus&&, double, double)> f7 = &Plus::plusd;
	cout << f7(move(pd), 1.1, 1.1) << endl;
	cout << f7(Plus(), 1.1, 1.1) << endl;
	return 0;
}

运行结果:

这里再提一下,静态成员函数也可以不加&

代码语言:javascript
复制
// 包装静态成员函数
function<int(int, int)> f4 = Plus::plusi;
cout << f4(1, 1) << endl;

2.2 bind

基本形式 (1)
代码语言:javascript
复制
template <class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
带返回类型的形式 (2)
代码语言:javascript
复制
template <class Ret, class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
功能说明

bind 是一个功能强大的函数模板,属于可调用对象包装器范畴。它本质上是一个函数适配器,允许开发者对输入的可调用对象 fn 进行参数绑定和调整,最终返回一个新的可调用对象。bind 的主要功能包括:

  1. 调整参数个数(减少或重新排列)
  2. 改变参数顺序
  3. 绑定部分参数值
  4. 使用占位符表示未绑定参数

该模板位于 <functional> 头文件中,是标准库提供的重要功能组件。

调用语法

典型的 bind 调用形式如下:

代码语言:javascript
复制
auto newCallable = bind(callable, arg_list);

其中:

  • newCallable 是生成的新可调用对象
  • callable 是原始可调用对象(函数、函数指针、成员函数、函数对象等)
  • arg_list 是以逗号分隔的参数列表,对应 callable 的参数

当调用 newCallable 时,它会自动调用原始 callable,并传递 arg_list 中绑定的参数。

占位符机制

arg_list 中可以包含特殊形式的占位符:

代码语言:javascript
复制
_n

其中 n 是正整数(如 _1, _2, _3 等),这些占位符表示:

  1. 该参数位置将由 newCallable 的调用者提供
  2. 数字 n 表示占位参数在 newCallable 参数列表中的位置:
    • _1 对应 newCallable 的第一个参数
    • _2 对应第二个参数
    • 依此类推

这些占位符定义在 std::placeholders 命名空间中,使用时需要:

代码语言:javascript
复制
using namespace std::placeholders;
// 或者
using std::placeholders::_1;
using std::placeholders::_2;
// ...
注意事项
  1. 占位符编号从 _1 开始,而不是 _0
  2. 可以混合使用固定值和占位符
  3. 当绑定成员函数时需要额外处理对象指针/引用
  4. 绑定参数时使用的是值语义,需要注意对象的生命周期

示例:

代码语言:javascript
复制
#include <functional>
#include <iostream>

using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int Sub(int a, int b)
{
	return (a - b) * 10;
}
int SubX(int a, int b, int c)
{
	return (a - b - c) * 10;
}
class Plus
{
public:
	static int plusi(int a, int b)
	{
		return a + b;
	}
	double plusd(double a, double b)
	{
		return a + b;
	}
};
int main()
{
	auto sub1 = bind(Sub, _1, _2);
	cout << sub1(10, 5) << endl;
	// bind 本质返回的一个仿函数对象
	// 调整参数顺序(不常用)
	// _1代表第一个实参
	// _2代表第二个实参
	// ...
	auto sub2 = bind(Sub, _2, _1);
	cout << sub2(10, 5) << endl;
	// 调整参数个数(常用)
	auto sub3 = bind(Sub, 100, _1);
	cout << sub3(5) << endl;
	auto sub4 = bind(Sub, _1, 100);
	cout << sub4(5) << endl;
	// 分别绑死第123个参数
	auto sub5 = bind(SubX, 100, _1, _2);
	cout << sub5(5, 1) << endl;
	auto sub6 = bind(SubX, _1, 100, _2);
	cout << sub6(5, 1) << endl;
	auto sub7 = bind(SubX, _1, _2, 100);
	cout << sub7(5, 1) << endl;
	// 成员函数对象进行绑死,就不需要每次都传递了
	function<double(Plus&&, double, double)> f6 = &Plus::plusd;
	Plus pd;
	cout << f6(move(pd), 1.1, 1.1) << endl;
	cout << f6(Plus(), 1.1, 1.1) << endl;
	// bind一般用于,绑死一些固定参数
	function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);
	cout << f7(1.1, 1.1) << endl;

	return 0;
}
一、std::bind 基本用法
1. 直接绑定函数(保持参数顺序)
代码语言:javascript
复制
auto sub1 = bind(Sub, _1, _2);
cout << sub1(10, 5) << endl;  // 输出: (10-5)*10 = 50
  • sub1(10, 5)Sub(10, 5)
  • 占位符顺序与参数顺序一致
2. 调整参数顺序
代码语言:javascript
复制
auto sub2 = bind(Sub, _2, _1);
cout << sub2(10, 5) << endl;  // 输出: (5-10)*10 = -50
  • sub2(10, 5)Sub(5, 10)
  • _2 对应第一个实参10,_1 对应第二个实参5

如图所示:

二、参数绑定技术
1. 绑定固定值
代码语言:javascript
复制
auto sub3 = bind(Sub, 100, _1);
cout << sub3(5) << endl;  // 输出: (100-5)*10 = 950

auto sub4 = bind(Sub, _1, 100);
cout << sub4(5) << endl;  // 输出: (5-100)*10 = -950
  • sub3(5)Sub(100, 5)
  • sub4(5)Sub(5, 100)
2. 多参数绑定
代码语言:javascript
复制
auto sub5 = bind(SubX, 100, _1, _2);
cout << sub5(5, 1) << endl;  // 输出: (100-5-1)*10 = 940

auto sub6 = bind(SubX, _1, 100, _2);
cout << sub6(5, 1) << endl;  // 输出: (5-100-1)*10 = -960

auto sub7 = bind(SubX, _1, _2, 100);
cout << sub7(5, 1) << endl;  // 输出: (5-1-100)*10 = -960
  • 分别固定第1、2、3个参数
  • 剩余参数通过占位符传递
三、成员函数绑定技术
1. 直接使用 std::function
代码语言:javascript
复制
function<double(Plus&&, double, double)> f6 = &Plus::plusd;
  • 函数类型:double(Plus&&, double, double)
  • 需要传递一个 Plus 对象作为第一个参数
代码语言:javascript
复制
Plus pd;
cout << f6(move(pd), 1.1, 1.1) << endl;  // 输出: 2.2

cout << f6(Plus(), 1.1, 1.1) << endl;     // 输出: 2.2
  • 传递左值对象(使用 std::move
  • 传递右值对象(临时对象)
2. 使用 std::bind 绑定对象
代码语言:javascript
复制
function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);
cout << f7(1.1, 1.1) << endl;  // 输出: 2.2
  • bind 固定了 Plus 对象(临时对象)
  • 创建只需两个参数的新函数对象
四、关键概念解析
1. std::bind 的返回值
代码语言:javascript
复制
// bind 本质返回的一个仿函数对象
auto sub1 = bind(Sub, _1, _2);
  • std::bind 返回一个未指定类型的函数对象
  • 通常用 auto 接收返回值
2. 成员函数绑定的本质
代码语言:javascript
复制
// 非静态成员函数需要对象上下文
bind(&Plus::plusd, Plus(), _1, _2)
  • 成员函数指针:&Plus::plusd
  • 第一个参数必须是类实例(对象、指针或引用)
  • Plus() 创建临时对象作为调用上下文
3. 对象传递方式

方式

示例

生命周期

值传递(临时对象)

bind(&T::func, T(), ...)

绑定对象在函数对象内

引用传递

bind(&T::func, ref(obj), ...)

依赖外部对象生命周期

指针传递

bind(&T::func, &obj, ...)

依赖外部对象生命周期

移动语义

bind(&T::func, move(obj), ...)

转移所有权到绑定对象

运行结果:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Lambda 表达式
    • 1.1 Lambda 表达式语法
    • 1.2 捕获列表
    • 1.3 Lambda 表达式的应用:现代 C++ 的简洁之道
      • 一、传统可调用对象的痛点
      • 二、Lambda 表达式的简洁优势
      • 三、Lambda 在实际开发中的典型应用
    • 1.4 lambda原理
      • 1. 编译器视角
      • 2. 捕获变量处理
  • 2. 包装器
    • 2.1 function 模板类
      • 基本特性
      • 使用示例
      • 性能特点
    • 2.2 bind
      • 基本形式 (1)
      • 带返回类型的形式 (2)
      • 一、std::bind 基本用法
      • 二、参数绑定技术
      • 三、成员函数绑定技术
      • 四、关键概念解析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档