C++11第四弹:包装器

2024-09-16 08:18:02 浏览数 (2)

包装器

包装器是一个类模板

C 中的可调用对象:函数指针(类型定义很复杂)、仿函数对象(定义一个类的时候,用的时候有些麻烦,其次不适合统一类型)、lambda(没有类型概念)、包装器

function包装器

function包装器 也叫作适配器。C 中的function本质是一个类模板,也是一个包装器。

std::function在头文件<functional> 类模板原型:

代码语言:javascript复制
template <class T> function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;

模板参数说明: Ret: 被调用函数的返回类型 Args…:被调用函数的形参

他不是用来定义可调用对象,是用来包装可调用对象:

代码语言:javascript复制
#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()
{
	function<int(int, int)> fc1;
	//包装函数指针
	function<int(int, int)> fc2 = f;
	cout << fc2(1, 2) << endl;
	//包装仿函数
	function<int(int, int)> fc3 = Functor();
	cout << fc3(2, 3) << endl;
	//包装lambda表达式
	function<int(int, int)> fc4 = [](int x, int y) {return x   y; };
	cout << fc4(3, 4) << endl;

	return 0;
}
应用场景

力扣:150.逆波兰表达式求值

代码语言:javascript复制
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;

        //命令和对应的函数动作结合
        map<string,function<int(int,int)>> opfuncMap={
            {" ",[](int a,int b){return a b;}},
            {"-",[](int a,int b){return a-b;}},
            {"*",[](int a,int b){return a*b;}},
            {"/",[](int a,int b){return a/b;}}
        };

        for(auto& str:tokens)
        {
            if(opfuncMap.count(str)) // 是操作符
            {
                function<int(int,int)> func=opfuncMap[str];
                int right=st.top();
                st.pop();
                int left=st.top();
                st.pop();
                st.push(func(left,right));
                
            }
            else //是操作数 
            {
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};
包装成员函数指针

在包装静态成员指针函数时,当我们需要用到某个函数时,需要在前面指定类域。但如果不是静态时,不仅需要添加类域,还需要添加一个&

代码语言:javascript复制
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)> fc1 = Plus::plusi;
	cout << fc1(1, 2) << endl;

	function<double(Plus*, double, double)> fc2 = &Plus::plusd;
	Plus plus;
	cout << fc2(&plus, 1.1, 2.2) << endl;
	
	function<double(Plus, double, double)> fc3 = &Plus::plusd;
	//Plus plus;
	cout << fc3(Plus(), 1.1, 2.2) << endl;

	return 0;
}

fc1 是一个 std::function<int(int, int)> 对象,绑定到静态成员函数 Plus::plusi。调用 fc1(1, 2) 输出 3

fc2 是一个 std::function<double(Plus*, double, double)> 对象,绑定到非静态成员函数 Plus::plusd。它接受一个 Plus* 指针和两个 double 类型的参数。调用 fc2(&plus, 1.1, 2.2) 计算 1.1 2.2 并输出 3.3

bind

std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺序调整等操作。

原型:

代码语言:javascript复制
template <class Fn, class... Args>
bind (Fn&& fn, Args&&... args);
with return type (2)	
template <class Ret, class Fn, class... Args>
bind (Fn&& fn, Args&&... args);

可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。

调用bind的一般形式:auto newCallable = bind(callable,arg_list);

调整参数顺序
代码语言:javascript复制
int Sub(int a, int b)
{
	return a - b;
}

int main()
{
	auto f1 = Sub;
	cout << f1(10, 5) << endl;

	auto f2 = bind(Sub, placeholders::_2, placeholders::_1);
	cout << f2(10, 5) << endl;

	return 0;
}
调整参数个数
代码语言:javascript复制
class Sub
{
public:
	int sub(int a, int b)
	{
		return a - b;
	}
};

int main()
{
	Sub sub;
	auto f3 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);
	cout << f3(10, 5) << endl;

	return 0;
}

参数顺序:bind(&Sub::sub, &s, _2, _1) 绑定了成员函数 sub s 对象,并指定 _2_1 的位置。调用 f3(10, 5) 会将 5 映射到 _210 映射到 _1,因此 f3(10, 5) 实际上会调用 s.sub(5, 10),结果是 5 - 10,即 -5

0 人点赞