c++11
也叫适配器。c++中的function本质是一个类模板,也是一个包装器
为什么需要fuction呢?
当一个类型既可以是函数指针,也可以是仿函数和lambda比倒是,函数指针的类型不好理解,仿函数写起来麻烦,lambda无法拿到类型,有什么办法有统一的函数对象
ret = func(x);
// 上面func可能是什么呢?那么func可能是函数名?函数指针?函数对象(仿函数对象)?也有可能
是lamber表达式对象?所以这些都是可调用的类型!如此丰富的类型,可能会导致模板的效率低下!
为什么呢?我们继续往下看
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()
{
// 函数名
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…:被调用函数的形参
void swap_func(int& r1, int& r2)
{
int tmp = r1;
r1 = r2;
r2 = tmp;
}
struct Swap
{
void operator()(int& r1, int& r2)
{
int tmp = r1;
r1 = r2;
r2 = tmp;
}
};
int main()
{
int x = 0, y = 1;
cout << x << " " << y << endl;
auto swaplambda = [](int& r1, int& r2) {
int tmp = r1;
r1 = r2;
r2 = tmp;
};
function<void(int&, int&)> f1 = swap_func;
f1(x, y);
cout << x << " " << y << endl << endl;
function<void(int&, int&)> f2 = Swap();
f2(x, y);
cout << x << " " << y << endl << endl;
function<void(int&, int&)> f3 = swaplambda;
f3(x, y);
cout << x << " " << y << endl << endl;
// 11:40继续
map<string, function<void(int&, int&)>> cmdOP = {
{"函数指针", swap_func},
{"仿函数", Swap()},
{"lambda", swaplambda},
};
cmdOP["函数指针"](x, y);
cout << x << " " << y << endl << endl;
cmdOP["仿函数"](x, y);
cout << x << " " << y << endl << endl;
cmdOP["lambda"](x, y);
cout << x << " " << y << endl << endl;
return 0;
}
类函数的包装
类函数需要指定域,成员函数第一个参数是this指针,需要传入
class Plus
{
public:
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return a + b;
}
};
int main()
{
// 成员函数取地址,比较特殊,要加一个类域和&
function<int(int, int)> f1 = &Plus::plusi;
cout << f1(1, 2) << endl;
//成员函数第一个参数默认是this指针
function<double(Plus*, double, double)> f2 = &Plus::plusd;
Plus ps;
cout << f2(&ps, 1.1, 2.2) << endl;
//和上面类似
function<double(Plus, double, double)> f3 = &Plus::plusd;
cout << f3(Plus(), 1.11, 2.22) << endl;
return 0;
}
类的函数调用每次都要写一个类,有点麻烦,有什么办法省略?
改造题目
https://leetcode.cn/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();
int ret = 0;
switch(str[0])
{
case '+':
ret = left + right;
st.push(ret);
break;
case '-':
ret = left - right;
st.push(ret);
break;
case '*':
ret = left * right;
st.push(ret);
break;
case '/':
ret = left / right;
st.push(ret);
break;
}
}else
{
st.push(stoi(str));
}
}
return st.top();
}
};
用包装器修改上面:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
map<string, function<int(int, int)>> cmdop =
{
{"+", [](int x, int y){return x + y;}},
{"-", [](int x, int y){return x - y;}},
{"*", [](int x, int y){return x * y;}},
{"/", [](int x, int y){return x / y;}}
};
for (auto str:tokens)
{
if (cmdop.count(str))
{
int right = st.top();
st.pop();
int left = st.top();
st.pop();
st.push(cmdop[str](left, right));
}
else
{
st.push(stoi(str));
}
}
return st.top();
}
};
bind
std::bind函数定义在头文件中,是一个函数模板,就像一个函数包装器(适配器),接受一个调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而言,我们用它把一个原本接收n个参数的函数fn,通过绑定一些参数,返回一个接收m个(m可以大于n,但没意义)参数的新函数。同时,还可以调整参数顺序
// 原型如下:
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为第二个参数,依次类推
//绑定第一个参数
function<double(double, double)> f4 = bind(Plus::plusd, Plus(), placeholders::_1, placeholders::_2);
cout << f4(1.11, 2.22) << endl;
int Sub(int a, int b)
{
return a - b;
}
//参数写死
function<int(int)> f6 = bind(Sub, 20, placeholders::_1);
cout << f6(5) << endl;
int Sub2(int a, int b, int c)
{
return a - b;
}
//中间写死
function<int(int, int)> f7 = bind(Sub2, placeholders::_1, 20, placeholders::_2);
cout << f7(5, 6) << endl;
return 0;