33 包装器

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;
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值