首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C++篇】C++11:包装器

【C++篇】C++11:包装器

作者头像
我想吃余
发布2025-08-11 08:30:09
发布2025-08-11 08:30:09
16800
代码可运行
举报
文章被收录于专栏:C语言学习C语言学习
运行总次数:0
代码可运行

function包装器

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

我们来看看,我们为什么需要function呢?

代码语言:javascript
代码运行次数:0
运行
复制
//函数模板
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);
}

//普通函数
double f(double i)
{
	 return i / 2;
}

//仿函数
struct Functor
{
	 double operator()(double d)
	 {
		 return d / 3;
	 }
};

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

通过上面的程序验证,我们会发现useF函数模板实例化了三份。 很浪费呀,那么有什么办法可以让useF只实例化一个模板也能传这3个不同类型的函数呢?

包装器可以很好的解决这个问题

function包装器原理

代码语言:javascript
代码运行次数:0
运行
复制
// 类模板原型如下
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
//模板参数说明:
//Ret: 被调用函数的返回类型
//Args…:被调用函数的形参

注意:std::function头文件<functional>

可以看到,包装function实际上就是用一个参数包,可以将不同类型的函数传到类中包装起来,使得不同类型的函数拥有一个统一类型function<T>,这样就可以实现函数模板只实例化一份也可传多种不同类型函数了。

包装方法如下:

std::function<函数返回值类型(函数参数类型)> func1 = 被包装函数

代码语言:javascript
代码运行次数:0
运行
复制
// 必须包头文件
#include <functional>

//普通函数
int f(int a, int b)
{
 	return a + b;
}

//仿函数
struct Functor
{
	 int operator() (int a, int b)
	 {
	 return a + b;
	 }
};

class Plus
{
public:
	 static int plusi(int a, int b)
	 {
	 	return a + b;
	 }
	 
	 double plusd(double a, double 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;
	 
	 // 也可以包装类的成员函数
	 std::function<int(int, int)> func4 = &Plus::plusi;
	 cout << func4(1, 2) << endl;
	 
	 std::function<double(Plus, double, double)> func5 = &Plus::plusd;
	 cout << func5(Plus(), 1.1, 2.2) << endl;
	 
	 return 0;
}

bind包装器

std::bind函数定义在头文件<functional>中,是一个函数模板。

它也是一种函数包装器(适配器),可以接受一个可调用对象(函数),生成一个新的可调用对象(新的函数)来“适应”原对象的参数列表。

一般而言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺序调整等操作。

bind原型如下:|

代码语言:javascript
代码运行次数:0
运行
复制
template <class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
// with return type (2) 
template <class Ret, class Fn, class... Args>
bind (Fn&& fn, Args&&... args);

模板参数说明:

  • fn:可调用对象。
  • args...:要绑定的参数列表:值或占位符

调用bind的一般形式为:auto newCallable = bind(callable, arg_list);

说明:

  • callable:需要包装的可调用对象。
  • newCallable:生成的新的可调用对象。
  • arg_list:是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。

占位符placeholders::_n: arg_list中的参数可能包含形如placeholders::_n的名字,其中n是一个整数,这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置,比如placeholders::_1为newCallable的第一个参数,placeholders::_2为第二个参数,以此类推。

使用示例如下:

无意义的绑定fun1 绑定固定参数fun2

代码语言:javascript
代码运行次数:0
运行
复制
#include <functional>

int Plus(int a, int b)
{
 	return a + b;
}

int main()
{
	 //表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定
	std::function<int(int, int)> func1 = std::bind(Plus, placeholders::_1, 
	placeholders::_2);

	 //func2的类型为 function<void(int, int, int)> 与func1类型一样
	 //表示绑定函数 plus 的第一,二参数为固定值: 1, 2
	 auto  func2 = std::bind(Plus, 1, 2);   
	 cout << func1(1, 2) << endl;
	 cout << func2() << endl;

绑定类的成员函数

当绑定类的成员函数,arg_list中第一个参数还是直接用函数名吗? 当然不是,成员函数是比较特殊的:

  • 对于普通成员函数:
    1. 取函数的地址(注意类的作用域)
    2. 传对象或者对象指针(因为一个类可以用多个对象,所以需要指定对象)
  • 对于静态成员函数:只需取函数的地址(因为一个类的所有对象共用一个静态成员变量,所以不需要指定对象)

示例如下:

代码语言:javascript
代码运行次数:0
运行
复制
#include <functional>

class Sub
{
public:
	 int sub(int a, int b)
	 {
		 return a - b;
	 }
	
	 static int sub(int a, int b)
	 {
		 return a - b;
	 }
};

int main()
{
	 Sub s;
	 // 绑定成员函数
	 std::function<int(int, int)> func1 = std::bind(&Sub::ssub, placeholders::_1, placeholders::_2);
	 std::function<int(int, int)> func2 = std::bind(&Sub::sub, s, 
	placeholders::_1, placeholders::_2);

调整传参顺序

调整传参只需改变arg_list中参数占位符的顺序即可

如图:

总结一下bind包装器的意义:

  1. 将一个函数的某些参数绑定为固定的值,让我们在调用时可以不用传递某些参数。
  2. 可以对函数参数的顺序进行灵活调整。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • function包装器
  • bind包装器
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档