不知道或者对lambda表达式不是很理解可以看一下这篇文章:C++11新特性:lambda表达式
以便对接下来的内容能够轻松吸收,好了开始进入正题。
目录
1 包装器
function包装器
function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。
那么我们来看看,我们为什么需要function呢?
#include<iostream> #include<functional> using namespace std; //ret = func(x); // 上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能 // 是lamber表达式对象?所以这些都是可调用的类型!如此丰富的类型,可能会导致模板的效率低下! // c为什么呢?我们继续往下看 template<class 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; } }; int main() { // 函数指针 double (*ptr) (double); ptr = &f; cout << useF(ptr, 11.11) << endl; // 函数名 cout << useF(f, 11.11) << endl; // 函数对象 cout << useF(Functor(), 11.11) << endl; // lamber表达式 cout << useF([](double d)->double{ return d/4; }, 11.11) << endl; return 0; }
通过上面的程序验证,我们会发现useF函数模板实例化了三份。
包装器可以很好的解决上面的问题std::function在头文件<functional> // 类模板原型如下 template <class T> function; // undefined template <class Ret, class... Args> class function<Ret(Args...)>; 模板参数说明: Ret: 被调用函数的返回类型 Args…:被调用函数的形参
#include <functional> #include<iostream> using namespace std; template<class 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; } }; int main() { // 函数名 std::function<double(double)> func1 = f; cout << useF(func1, 11.11) << endl; // 函数对象 std::function<double(double)> func2 = Functor(); cout << useF(func2, 22.22) << endl; // lambda表达式 std::function<double(double)> func3 = [](double d)->double {return d / 4;}; cout << useF(func3, 11.11); return 0; }
包装器的其他一些场景:
https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/submissions/
class Solution { public: int evalRPN(vector<string>& tokens) { stack<int> st; for(auto& str : tokens) { if(str == "+" || str == "-" || str == "*" || str == "/") { int right = st.top(); st.pop(); int left = st.top(); st.pop(); switch(str[0]) { case '+': st.push(left+right); break; case '-': st.push(left-right); break; case '*': st.push(left*right); break; case '/': st.push(left/right); break; } } else { // 1、atoi itoa // 2、sprintf scanf // 3、stoi to_string C++11 st.push(stoi(str)); } } return st.top(); } }; // 使用包装器以后的玩法 class Solution { public: int evalRPN(vector<string>& tokens) { stack<int> st; map<string, function<int(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; } } }; for(auto& str : tokens) { if(opFuncMap.find(str) != opFuncMap.end()) { int right = st.top(); st.pop(); int left = st.top(); st.pop(); st.push(opFuncMap[str](left, right)); } else { // 1、atoi itoa // 2、sprintf scanf // 3、stoi to_string C++11 st.push(stoi(str)); } } return st.top(); } };
2 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为第二个参数,以此类推。// 使用举例 #include <functional> #include <iostream> using namespace std; int Plus(int a, int b) { return a + b; } class Sub { public: int sub(int a, int b) { return a - b; } static ssub(int a, int b) { return a-b-b; } }; int main() { //表示绑定函数plus 参数分别由调用 func1 的第一,二个参数指定 std::function<int(int, int)> func1 = std::bind(Plus, placeholders::_1, placeholders::_2); //auto func1 = std::bind(Plus, placeholders::_1, placeholders::_2); //func2的类型为 function<void(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::function<int(int, int)> func3 = std::bind(&Sub::sub, s, placeholders::_1, placeholders::_2); // 绑定静态成员函数 std::function<int(int, int)> func4 = std::bind(&Sub::ssub, placeholders::_1, placeholders::_2); // 参数调换顺序 std::function<int(int, int)> func5 = std::bind(&Sub::sub, s, placeholders::_2, placeholders::_1); cout << func3(1, 2) << endl; cout << func4(1, 2) << endl; cout << func5(1, 2) << endl; return 0; }