目录
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; }
- std::function<int(int, int)> func4 = &Plus::plusi; 静态成员函数可以省略&取地址符号(推荐不省略以免搞混);因为静态成员函数可以使用:类名::静态成员函数使用
- std::function<double(Plus, double, double)> func5 = &Plus::plusd;普通成员函数不可以使用类名::静态成员函数名类使用;必须要有一个对象来访问,&取地址符号也不可以省略;所以多了一个参数;绑定可以解决多一个参数的问题
2.2bind
bind是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表
- 通过bind调整参数顺序
- 通过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的参数很明确;