C++11新特性:包装器 + bind

 不知道或者对lambda表达式不是很理解可以看一下这篇文章:C++11新特性:lambda表达式

以便对接下来的内容能够轻松吸收,好了开始进入正题。

目录

1 包装器

2 bind


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


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值