C++ 包装器function

        目录

1、为什么需要包装器?

2、包装器的声明和使用

(1) 声明

(2) 实际应用

(3) 包装器接收类成员函数

3、包装器的绑定:bind函数

(1) 调整参数顺序

(2) 调整参数个数


1、为什么需要包装器?

函数模板可以接收各种不同类型的参数,即便是普通函数、仿函数、lamda表达式也可以接收,但是在实例化的时候,即便形参和返回值完全一样,因为是不同类型,所以需要实例化多份代码。

所以包装器的作用是统一传入的函数对象(前提是不同函数的形参和返回值都要一样),最终只需实例化出一份代码,从而达到提高效率的目的。

// 要传入的函数 / 表达式
int func_add(int x, int y)
{
	return x + y;
}

struct Add {
	int operator()(int x, int y)
	{
		return x + y;
	}
};

auto lamda_add = [](int x, int y) -> int {
	return x + y;
};

// 函数模板
template<class F>
void test_add(F f, int x, int y)
{
	cout << typeid(F).name() << endl;
	f(x, y);
}

2、包装器的声明和使用

(1) 声明

包装器的作用是为了统一传递给模板的函数对象,不同函数的形参和返回值必须一致。

头文件:functional

语法格式:std::function<返回值(形参类型1,形参类型2,...)>  = 函数名 / 函数对象

// 函数func_add,对应的包装器f1
function<int(int, int)> f1 = func_add;
test_add(f1, 10, 20);

// 仿函数Add(),对应的包装器f2
function<int(int, int)> f2 = Add();
test_add(f2, 10, 20);

// lamda表达式lamda_add,对应的包装器f3
function<int(int, int)> f3 = lamda_add;
test_add(f3, 10, 20);

我们会发现不同函数经过包装以后,函数对象的类型都是 function<int(int, int)>,我们再看一下实际调用的结果。

(2) 实际应用

有了包装器,我们可以使用不同的指令来调用不同的函数,以最简答的四则运算为例3

(3) 包装器接收类成员函数

包装器其实也可以接收类的成员函数,包装器接收的是类成员对象的函数地址,使用包装器时需要多传递一个匿名对象,因为实际上是使用匿名对象去调用类成员函数。

class Adds {
public:
	int add(int x, int y) {
		return x + y;
	}
};

int main()
{
    function<int(Adds, int, int)> f4 = &Adds::add;    // 注意这里必须要取地址
    f4(Adds(), 10, 20);
}

结合下面介绍的绑定bind,我们可以在声明的时候就让包装器绑定匿名对象,在实际调用的时候,我们就无需传递匿名对象了。

function<int(int, int)> f4 = bind(&Adds::add, Adds(), placeholders::_1, placeholders::_2);
// f4(10, 20);
test_add(f4, 10, 20);

 

3、包装器的绑定:bind函数

包装器的绑定主要用于调整参数,比如调整顺序、调整参数个数。上面使用包装器接收类的成员函数便是bind的一种应用场景。

既然是调整参数,bind函数是如何获取到包装器对应的函数参数呢?

  • placeholders::_1  表示函数的第一个参数
  • placeholders::_2  表示函数的第二个参数
  • ...
  • 以此类推,bind函数最多可以调整20个参数

(1) 调整参数顺序

首先,我们定义一个简单的lamda表达式,打印传入的内容;

其次,我们使用bind函数调整第一个参数和第二个参数的顺序,再次打印传入的内容。

auto print = [](int x, int y) -> int{
	cout << x << " " << y << endl;
	return 0;
};

cout << "调整参数之前:";
print(10, 20);	// 调整参数之前
function<int(int, int)> func = bind(print, placeholders::_2, placeholders::_1);
cout << "调整参数之后:";
func(10, 20);	// 调整参数之后

 

(2) 调整参数个数

调整参数个数,其实也可以理解为设置缺省值,设置缺省值以后,有些参数就无需重复传递参数

class Adds {
public:
	int add(int x, int y) {
		return x + y;
	}
};

// 正常包装
function<int(Adds, int, int)> f4_1 = &Adds::add;    // 注意这里必须要取地址
f4_1(Adds(), 10, 20);

// 修改参数个数后包装 (将对象设为缺省)
function<int(int, int)> f4_2 = bind(&Adds::add, Adds(), placeholders::_1, placeholders::_2);
f4_2(10, 20);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值