【C++重点语法下】可变参数模板,STL里面的push_back和emplace_back区别 ,包装器function,bind

目录

1.可变参数模板

        1.1取出参数包内的参数方法一:

        1.2取出参数包内的参数方法二:  

        1.3STL里面的push_back和emplace_back区别 

2.包装器function

       2.1function(头文件functional)

        2.1.1可调用类型和包装器 

                2.1.2类的成员函数和包装器 

        2.2bind


1.可变参数模板

参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。 

//argument翻译:参数
template <class ...Args>
void ShowList(Args... arg)
{
	cout << sizeof...(arg) << endl;
	cout << sizeof...(Args) << endl<< endl;
}
int main()
{
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1, 'A', std::string("sort"));

	return 0;
}

使用sizeof需要在(变量)之前加...,即可算出参数包内的个数 

1.1取出参数包内的参数方法一:

递归调用 

template<class T,class ...Args>
// 解析并打印参数包中每个参数的类型及值
void ShowList(T val, Args...args)
{
	cout << typeid(T).name() << " " << val << endl;
	ShowList(args...);
}

执行结果:参数包的元素在递归中会被拿完;但是至少应该有一个参数才可以继续递归(参数包的参数可以为0-n),但是T必须有参数实例化;而且没有递归调用结束条件; 

 

// 递归终止函数
template<class T>
void ShowList(T val)
{
	cout << typeid(T). name() << " " << val << endl << endl;
}
template<class T,class ...Args>
 解析并打印参数包中每个参数的类型及值
void ShowList(T val, Args...args)
{
	cout << typeid(T).name() << " " << val << endl;
	ShowList(args...);
}

int main()
{
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1, 'A', std::string("sort"));
	return 0;
}

执行结果:

1.2取出参数包内的参数方法二:  

    int arr[] = { PrintArg(args)... };很奇怪的语法,只有硬背 

  • { PrintArg(args)... };把这个展开;有几个参数就展开几个,比如参数包内有3个参数,int arr[]={PrintArg(args),PrintArg(args),PrintArg(args)};
template <class T>
int PrintArg(T val)
{
	T copy(val);
	cout << typeid(T).name() << ":" << val << endl;
}

//展开函数
template <class ...Args>
void ShowList(Args... args)
{
	int arr[] = { PrintArg(args)... };
	cout << endl;
}
int main()
{
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1, 'A', std::string("sort"));
	return 0;
}

执行结果:

1.3STL里面的push_back和emplace_back区别 

  • push_back是左值和右值的引用;emplace_back是万能引用
  • emplace_back使用的是参数包
  • 右值:emplace_back是:直接使用参数构造;push_back是使用参数先构造临时对象,再资源转移
  • 左值:都是直接使用左值拷贝构造
  • emplace_back在右值比push_back效率高一点点;优化了但是只能优化一点点;

2.包装器function

ret = func(x);

上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能是lamber表达式对象?

  • 例lambda表达是:auto fun=[](int a,int b)->int{return a+b;};
template<class F, class T>
void useF(F f, T x)
{
	static int count = 0;
	cout << "count:" << ++count << endl;
	cout << "count:" << &count << endl;
}
//普通函数
double f(double i)
{
	return i / 2;
}

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

执行结果:static修饰的局部变量声明周期变长,如果实例化的是一份;应该是1,2,3;且地址不同说明不是一个;

结论:将实例化出3份,效率低,有没有办法实例化一份就好

先看下面,懂了再来看这几句代码

	std::function<double(double)> func1 = f;
	useF(func1, 11.11);
	// 函数对象
	std::function<double(double)> func2 = Functor();
	useF(func2, 11.11);
	// lamber表达式
	std::function<double(double)> func3 = [](double d)->double { return d /4; };
	useF(func3, 11.11);

 2.1function(头文件functional)

2.1.1可调用类型和包装器 

#include <functional>
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;
}

执行结果: 

2.1.2类的成员函数和包装器 

 类的成员函数和包装器 

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)> 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;
}

  1. std::function<int(int, int)> func4 = &Plus::plusi; 静态成员函数可以省略&取地址符号(推荐不省略以免搞混);因为静态成员函数可以使用:类名::静态成员函数使用
  2. std::function<double(Plus, double, double)> func5 = &Plus::plusd;普通成员函数不可以使用类名::静态成员函数名类使用;必须要有一个对象来访问,&取地址符号也不可以省略;所以多了一个参数;绑定可以解决多一个参数的问题

 2.2bind

bind是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表

  1. 通过bind调整参数顺序
  2. 通过bind调整参数个数

通过bind调整参数顺序 

int SubFunc(int x, int y)
{
	return x - y;
}
int main()
{
	function<int(int, int)> func1 = SubFunc;
	cout << func1(10, 5) << endl;
	//没有改变参数顺序
	function<int(int, int)> func2 = bind(SubFunc, placeholders::_1, placeholders::_2);
	cout << func2(10, 5) << endl;
	//交换参数顺序
	function<int(int, int)> func3 = bind(SubFunc, placeholders::_2, placeholders::_1);
	cout << func3(10, 5) << endl;
	return 0;
}

  

 通过bind调整参数个数

class Add
{
public:
	int add(int x, int y)
	{
		return x + y;
	}
};
int main()
{
	//需要对象来调用普通函数
	function<int(Add, int, int)> func4 = &Add::add;
	cout << "func4:" << func4(Add(), 10, 20) << endl;
	//使用bind改变参数个数
	function<int(int, int)> func5 = bind(&Add::add,Add(), placeholders::_1, placeholders::_2);
	cout << "func5:" << func5(10, 20) << endl;
	return 0;
}

可以使用auto接受,但是function的参数很明确; 

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值