C++_Function包装器和bind


前言

到目前为止的学习,我们知晓了三种方式来传函数。

第一种

#include<iostream>

int Plus(int i, int j)
{
	return i + j;
}

int main()
{
	int(*func)(int, int) = Plus;
	std::cout << func(4, 5) << std::endl;
}

这种方式是C语言就支持的写法,但是实在繁琐,且没有一定C语言功底不易理解。

第二种 仿函数

class Func {
public:
	Func(){} //无参构造函数

	int operator()(int i, int j)
	{
		return i + j;
	}
private:
};

int main()
{
	std::cout << Func()(1, 2) << std::endl;;
	Func f1;
	std::cout << f1(4, 5) << std::endl;;
	return 0;
}

很多容器例如map,set类就可以传仿函数进去。

第三种 lambda表达式

void Plus(int i, int j)
{
	std::cout << i + j << std::endl;
}

int main()
{
	std::thread t1([](int i, int j) {std::cout << i + j<< std::endl; },1 ,2);
	std::thread t2(Plus,1 ,2);
	t1.join();
	t2.join();
	return 0;
}

lambda的本质其实就是仿函数,但是lamda表达式有一个缺点就是不好确定类型,在一些例如map对象的定义时,模版的实例化不好确定类型。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Function包装器

基于上面的三种不同的传函数方式,C++11提供Function来对函数进行一个整体的包装,将类型统一化,更加具有实用性和方便性。

需要包头文件 #include< functional >

int plus(int i, int j)
{
	return i + j ;
}

class Func {

public:
	Func(){} //无参构造函数

	int operator()(int i, int j)
	{
		return i + j;
	}
private:

};

class Plus {
public:
	static int plus(int i, int j)
	{
		return i + j;
	}

	int Add(int i, int j)
	{
		return i + j;
	}
};
int main()
{
	//函数名
	std::function<int(int, int)> f1(plus);

	//仿函数对象
	std::function<int(int, int)> f2 = Func();

	//lambda表达式
	std::function<int(int, int)> f3([](int i, int j) { return i + j; });


	//类的静态成员函数
	std::function<int(int, int)> f4(&Plus::plus);

	//类的成员函数
	//需要一个函数对象来调用
	std::function<int(Plus, int, int)> f5(&Plus::Add);

	std::cout << f1(1, 2) << std::endl;
	std::cout << f2(2, 3) << std::endl;
	std::cout << f3(3, 4) << std::endl;
	std::cout << f4(5, 6) << std::endl;
	std::cout << f5(Plus(),6, 7) << std::endl;
	return 0;
}

二、使用场景

LeetCode_逆波兰表达式求值
力扣这一题就可以很好反映function的使用,需要使用到操作函数来解题。
我们如果要使用map来映射操作符号和对应函数,就可以使用function来包装。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        std::stack<int> st;
        std::map<string,function<int(int,int)>> func = {
            {"+",[](int left, int right){return left + right;}},
            {"-",[](int left, int right){return left - right;}},
            {"*",[](int left, int right){return left * right;}},
            {"/",[](int left, int right){return left / right;}}     };

        for(auto str: tokens)
        {
            if(func.find(str) != func.end())
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                st.push(func[str](left,right));
            }
            else
            {
                st.push(std::stoi(str));
            }
        }

        return st.top();
    }
};

三、std::bind

bind也可以理解为一个函数包装器,接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。

int minus(int i, int j)
{
	return i - j;
}

int main()
{
	//生成的新func1与plus一致
	auto func1 = std::bind(minus, std::placeholders::_1, std::placeholders::_2);
	std::cout << "func1: " << func1(5, 1) << "   plus: " << minus(5, 1) << std::endl;

	//生成的新func2参数调换
	auto func2 = std::bind(minus, std::placeholders::_2, std::placeholders::_1);
	std::cout << "func2: " << func2(5, 1) << "   plus: " << minus(5, 1) << std::endl;

	//生成的新func3,func4,func5参数数量改变
	auto func3 = std::bind(minus, 5, std::placeholders::_1);
	std::cout << "func2: " << func3(1) << "   plus: " << minus(5, 1) << std::endl;

	auto func4 = std::bind(minus, std::placeholders::_1, 1);
	std::cout << "func2: " << func4(5) << "   plus: " << minus(5, 1) << std::endl;

	auto func5 = std::bind(minus, 5, 1);
	std::cout << "func2: " << func5() << "   plus: " << minus(5, 1) << std::endl;

	return 0;
}

在这里插入图片描述
std::placeholders::_n 在这里作为“占位符”,代表newCallable的参数,它们占据了传递给newCallable的参数的“位置”,数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。

从上面的例子中,我们可以看出bind不仅可以使新生成的可调用对象的参数顺序变化,还可以固定某个参数的值和改变参数个数。 但是看上去并不实用? 那么在哪里实用呢?

例如再上面我们讲的

	//类的成员函数
	//需要一个对象来调用
	std::function<int(Plus, int, int)> f5(&Plus::Add);

这里使用function对类的成员函数进行包装,需要传一个对象才可以,与其它的函数包装还不一样,通过bind我们就可以这样传。

class Plus {
public:
	int Add(int i, int j)
	{
		return i + j;
	}
};

int main()
{
	auto func1 = std::bind(&Plus::Add, Plus(), std::placeholders::_1, std::placeholders::_2);
	std::cout << "func1: " << func1(1, 2) << "    Plus::Add: " << Plus().Add(1, 2) << std::endl;


	std::function<int(Plus, int, int)> f5(&Plus::Add);
	std::function<int(int, int)> func2 = std::bind(f5, Plus(), std::placeholders::_1, std::placeholders::_2);
	std::cout << "func2: " << func2(1, 2) << "    f5: " << f5(Plus(), 1, 2) << std::endl;


	return 0;
}

在这里插入图片描述
这种场景下,我们就可以使用bind来创建一个新的可调用对象来少传一个临时对象。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风君子吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值