C++11--包装器与可变参数摸板

可变参数模板

C++11的新特性可变参数模板能够让我们创建可以接受可变参数的函数模板和类模板

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args... args,这个擦拭农户包中可以包含0到任意个模板参数
template<class ...Args>
void show(Args... args){}

上面的参数args前面有省略号,所以它就是一个可变模板参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N个模板参数。我们无法直接获取参数包args中的每个参数,只能通过展开参数包的方式来获取参数包中的每个参数。

递归函数方式展开参数包
#include <iostream>
using namespace std;
// 递归终止函数
template<class T>
void showlist(T t)
{
	cout << t << endl; // 当参数包只剩下最后一个参数时,会适配这个函数
}

// 递归函数
template <class T, class ...Args>
void showlist(T val, Args... args)
{
	cout << val << endl;
	showlist(args...); // 通过递归调用,函数会自动适配参数个数,此处的三个...不能省略
}

int main()
{
	showlist(1);
	showlist(1, "fff");
	showlist(3, 1.1, string("hello"));
	return 0;
}

在这里插入图片描述

函数包装器

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

我们都知道一个函数func有可能是一个函数,有可能是一个函数指针,有可能是一个仿函数,也有可能是一个lambda表达式。这些都是可调用的类型,如此丰富的类型,可能会导致模板的效率低下。q

举个例子
#include <iostream>
using namespace std;
template <class T, class F>
void func(T t, F f)
{
	static int a = 0; // 如果模板只实例化一次,每个a的地址是一样的
	cout << &a << endl;
}

int main()
{
	func(1, 1);
	func(1, 1.1);
	func('1', 2);
	return 0;
}

在这里插入图片描述

可以发现通过函数模板去实例化的函数是三分不同的函数。

// 通过函数包装器使用函数
#include <functional>
#include <iostream>
#include <functional>

template <class T, class F>
void fun(T t, F f)
{
	static T x;
	x = t;
	std::cout << typeid(t).name() << std::endl;
}

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

	static int mul(int x, int y)
	{
		return x * y;
	}
};

int main()
{
	functest ft;
	// 使用包装器,包装成员函数,需要加上类类型
	std::function<int(functest,int, int)> f1 = &functest::add;
	std::cout << f1(functest(),1, 2) << std::endl;
	// 使用包装器,包装静态成员函数,不需要加上类类型
	std::function<int(int, int)> f2 = &functest::mul;
	std::cout << f2(2, 3) << std::endl;
	// 使用包装器包装lambda表达式
	double x = 1.2;
	std::function<double(double)> f3 = [&](double y)->double { return x *= y; };
	std::cout << f3(4) << std::endl;
	return 0;
}

bind函数

std::bind函数定义在头文件中,是一个函数模板,他像一个函数包装器(适配器),接受一个可调用对象,生成一个新的可调用对象来“适应”对象的参数列表。一般而言,我们用它可以把一个原本接收N个参数的函数,通过绑定一些参数,返回一个接收M个(M可以大于N)参数的新函数。同时,使用std::bind函数还可以实现参数顺序调整等操作。

// bind函数的原型
template <class Fn, class ...Args>
bind(Fn&&, Args&& ...args);

可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表,使用方法如下:

auto newCallable = bind(callable, arg_list);
举个例子
// bind函数使用举例
#include<iostream>
#include<functional>

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

	
};

double mutl(double x, double y)
{
	return x * y;
}

int main()
{
	// 将mutl函数的第一个参数固定为1,后面在调用函数的时候只需要传一个参数
	std::function<double(double)> fun1 = std::bind(mutl, 1 , placeholders::_1);
	std::cout << fun1(2.1) << std::endl;
	// 使用bind函数绑定成员变量
	std::function<int(int, int)> fun2 = std::bind(&functest::add, functest(), placeholders::_1, placeholders::_2);
	std::cout << fun2(1, 2) << std::endl;
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_yiyi_

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值