包装器1.1 function包装器function包装器 也叫作适配器。C中的function本质是一个类模板也是一个包装器。templateclass 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; } }; void test1() { // 函数指针 std::cout useF(f, 11.11) std::endl; // 函数对象仿函数 std::cout useF(Functor(), 11.11) std::endl; // lamber表达式 std::cout useF([](double d)-double { return d / 4; }, 11.11) std::endl; }通过上面的程序验证我们会发现useF函数模板实例化了三份。包装器可以很好的解决上面的问题function在头文件functional类模板原型如下template class T function; // undefined template class Ret, class... Args class functionRet(Args...);模板参数说明Ret : 被调用函数的返回类型Args…被调用函数的形参1.2包装器的使用有了包装器我们就可以把上面的三份不同的对象存储到一个vector中void test2() { //包装器 functiondouble(double) f1 f;//函数指针 functiondouble(double) f2 Functor();//仿函数对象 functiondouble(double) f3 [](double d)-double { return d / 4; };//lambda vectorfunctiondouble(double) v { f1,f2,f3 }; double n 3.14; for (auto f : v) { cout f(n) endl; } }使用方法如下int f(int a, int b) { return a b; } struct Functor { public: 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; } }; void test4() { // 函数名(函数指针) std::functionint(int, int) func1 f; cout func1(1, 2) endl; // 函数对象 std::functionint(int, int) func2 Functor(); cout func2(1, 2) endl; // lamber表达式 std::functionint(int, int) func3 [](const int a, const int b) {return a b; }; cout func3(1, 2) endl; // 类的成员函数 std::functionint(int, int) func4 Plus::plusi; cout func4(1, 2) endl; std::functiondouble(Plus, double, double) func5 Plus::plusd; cout func5(Plus(), 1.1, 2.2) endl; }1.3包装器的应用给你一个字符串数组tokens 表示一个根据逆波兰表示法表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。class Solution { public: int evalRPN(vectorstring tokens) { stackint st; mapstring, functionint(int, int) opFuncMap { { , [](int i, int j) {return i j; } }, { -, [](int i, int j) {return i - j; } }, { *, [](int i, int j) {return i * j; } }, { /, [](int i, int j) {return i / j; } }, { , [](int i, int j) {return i j; } } }; for (auto str : tokens) { if (opFuncMap.find(str) ! opFuncMap.end()) { //操作符 int right st.top(); st.pop(); int left st.top(); st.pop(); //通过[]去调用包装器的lambda st.push(opFuncMap[str](left, right)); } else { //操作数 // 1、atoi itoa // 2、sprintf scanf // 3、stoi to_string C11 st.push(stoi(str)); } } return st.top(); } };1.4 bind包装器std::bind函数定义在头文件中是一个函数模板它就像一个函数包装器(适配器)接受一个可调用对象callable object生成一个新的可调用对象来“适应”原对象的参数列表。一般而言我们用它可以把一个原本接收N个参数的函数fn通过绑定一些参数返回一个接收M个M可以大于N但这么做没什么意义参数的新函数。同时使用std::bind函数还可以实现参数顺序调整等操作。/原型如下template class Fn, class... Args /* unspecified */ bind(Fn fn, Args... args); // with return type (2) template class Ret, class Fn, class... Args /* unspecified */ bind(Fn fn, Args... args);可以将bind函数看作是一个通用的函数适配器它接受一个可调用对象生成一个新的可调用对象来“适应”原对象的参数列表。调用bind的一般形式auto newCallable bind(callable, arg_list);其中newCallable本身是一个可调用对象arg_list是一个逗号分隔的参数列表对应给定的callable的参数。当我们调用newCallable时newCallable会调用callable, 并传给它arg_list中的参数。arg_list中的参数可能包含形如_n的名字其中n是一个整数这些参数是“占位符”表示newCallable的参数它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置_1为newCallable的第一个参数_2为第二个参数以此类推。1.5 bind包装器的使用例1int sub(int x, int y) { return x - y; } void test5() { //保持x-y不变 functionint(int, int) resub1 bind(sub, placeholders::_1, placeholders::_2); cout resub1(10, 5) endl; //交换x,y相减 functionint(int, int) resub2 bind(sub, placeholders::_2, placeholders::_1); cout resub2(10, 5) endl; }例2int Plus(int a, int b) { return a b; } class Sub { public: int sub(int a, int b) { return a - b; } static int plus(int a, int b) { return a b; } }; void test6() { //表示绑定函数plus 参数分别由调用 func1 的第一二个参数指定 std::functionint(int, int) func1 std::bind(Plus, placeholders::_1,placeholders::_2); //auto func1 std::bind(Plus, placeholders::_1, placeholders::_2); //func2的类型为 functionvoid(int, int, int) 与func1类型一样 //表示绑定函数 plus 的第一二为 1 2 auto func2 std::bind(Plus, 1, 2); cout func1(1, 2) endl; cout func2() endl; Sub s; // 绑定成员函数 //绑定参数不参与后面的排序 std::functionint(int, int) func3 std::bind(Sub::sub, s,placeholders::_1, placeholders::_2); //对于非静态的类域中的函数要加上一个定义的对象 functionint(int, int) func4 bind(Sub::sub, s,placeholders::_2, placeholders::_1); //传匿名对象最方便 functionint(int, int) func5 bind(Sub::sub, Sub(), placeholders::_2, placeholders::_1); cout func3(1, 2) endl; cout func4(1, 2) endl; //对于静态的类域的函数 functionint(int, int) func6 bind(Sub::plus, placeholders::_2, placeholders::_1); }注意bind在传类的成员函数的时候如果该函数是静态的就正常传如果该函数不是静态的就需要传类的地址并且还需要传一个类的对象或者对象的指针。总结也就是当我们需要对一些函数接口进行传参顺序的改变就可以使用bind包装器。