c++function bind包装器详解

包装器

function包装器

  • function包装器也叫适配器,c++中的function本质是一个类模板,也是一个包装器,那么为什么需要包装器呢。
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;
}

运行结果:

candy:~/code/cpp/test/tuple $  ./a.out 
count:1
count:0x5624be36c15c
5.555
count:1
count:0x5624be36c160
3.70333
count:1
count:0x5624be36c158
2.7775

​ 对于一个ret = func(x),我们并不知道func是什么,func可能是函数指针,也可能是函数名,仿函数,lambda表达式,所以这些都是可调用的类型,这样就会导致模板的效率低下,就如同我刚写的代码,count的地址是不一样的,这就是说函数模板实例化出来了多份,而包装器就可以很好的解决这个问题。

function说明

std::function在头文件<functional>

// 类模板原型如下
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
模板参数说明:

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

function的使用

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;
 	}

};


int main(){
	//绑定普通函数
	function<int(int, int)> f1 = f;
	cout << f1(2,3) << endl;
	//绑定仿函数
	function<int(int,int)> f2 = Functor();
	cout << f2(3,4) << endl;
	//绑定lambda表达式
	function<int(int,int)> f5 = [](int a, int b){ return a+b; };
	cout << f5(323,3243) << endl;
	//绑定类静态成员函数  -> 要指定类域
	function<int(int,int)> f3 = Plus::plusi;
	cout << f3(32,32) << endl;
	//绑定非静态成员函数:
	//1.首先非静态成员函数的函数指针要加上&符号
	//2.因为非静态成员函数中还有一个隐藏的参数 -> this指针,所以要显示的传递一个类的对象或者指针
	function<double(Plus,double,double)> f4 = &Plus::plusd;
	Plus p1;
	cout << f4(p1, 1.1,1.32) << endl;
	return 0;
}

​ 这里除了非静态成员变量的使用有两点要注意以外,其余的使用都比较简单,那么为什么function可以解决模板低效的问题呢 -> function 完成了对类型的统一

#include <functional>

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, 11.11) << endl;
 	// lamber表达式

 	std::function<double(double)> func3 = [](double d)->double{ return d / 4; };
 	cout << useF(func3, 11.11) << endl;
 	return 0;
}

运行结果:

candy:~/code/cpp/test/tuple $  g++ test.cc 
candy:~/code/cpp/test/tuple $  ./a.out 
count:1
count:0x564b0f7cb154
5.555
count:2
count:0x564b0f7cb154
3.70333
count:3
count:0x564b0f7cb154
2.7775

​ 可以看到这里的count的地址都是相同的,这就统一了类型的问题,而function的好处还不止这些,试想一下如果要存储对应的string和函数的关系,我们要如何存储,在c++11之前或许需要使用函数指针来进行操作,但是函数指针相对来说阅读起来观感并不好,但是现在一个function就可以解决这个问题。

请添加图片描述

对于这样的一个题,我们就可以使用function来统一类型使用map来进行管理

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> v;
        unordered_map<string, function<int(int,int)>> op = {
            {"+", [](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 e : tokens){
            if(op.count(e)){
                int right = v.top();
                v.pop();
                int left = v.top();
                v.pop();
                v.push(op[e](left, right));
            }
            else{
                v.push(stoi(e));
            }
        }
        return v.top();
    }
};

bind

  • std::bind定义在functional头文件中,是一个函数模板,他就是一个函数包装器(适配器),接收一个可调用对象(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为第二个参数,以此类推。

eg:

// 使用举例

#include <functional>

int Plus(int a, int b)
{
 	return a + b;
}

class Sub
{
public:
 	int sub(int a, int b)
 	{
 	return a - 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::sub,s, placeholders::_2,placeholders::_1);
 	cout << func3(1, 2) << endl; 
 	cout << func4(1, 2) << endl;
 	return 0;
}

  • 这里除了可以这样让非静态成员变量少传一个参数之外,还可以绑定一写必须要传的参数从而减少参数个数。
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值