C++11之 std::bind | std::function

std::function仿函数对象

std::function<… …>用来声明函数对象的,换句话说,就和函数指针、Lambda表达式、函数名是一个东西。

std::bind就是将一个函数对象绑定成为另一个函数对象,std::bind的返回值类型是std::function。


头文件 #include <functional>
命名空间 stdstd::placeholders

bind使用时的注意细节:
① bind的第一个参数必须要加取地址符号&
② 必须加上using namespace std::placeholders,否则找不到占位符


代码是最好的老师,二话不说,先看std::bind、std::function使用的代码

void showAll(int a, double b, const std::string& c)
{
	std::cout << a << "; " << b << "; " << c << std::endl;
}
void test()
{
	using namespace std::placeholders;

	std::function<void(int, double)> output = 
				std::bind(&showAll, _1, _2, "Kobe");
	output(1, 2);
}

观看代码,可以很明显的看到下面规律:
bind中占位符的个数 = 调用时传递的实参的个数 = function<>中参数类型的个数
② std::bind用于对函数对象进行适配,适配成std::function<void(int, double)>类型


std::bind绑定器

(1)首先,std::bind也是一个函数模板,返回值是一个仿函数,也是可调用对象。它的作用与bind1st和bind2st类似,是这两个函数的加强版。但极大地提高了灵活性,可以完全替代bind1st和bind2nd。
(2)bind的作用主要就是将可调用对象变成std::function对象(即仿函数对象),主要体现在两个方面。
  ①将多元的可调用对象与其参数一起绑定成一个仿函数对象
  ②将多元(设参数个数为n)的可调用对象转成一元或(n-1)元的可调用对象,即只绑定部分参数。
(3)std::bind可以绑定的对象(注意bind的返回值是仿函数)
  ①全局函数、静态全局函数 √
  ②类的static成员函数√
  ③类的非static成员函数(注意:_1必须是某个对象的地址)
  ④函数对象 / 仿函数- STL的仿函数、std::function √
  ⑤类的数据成员(注意:_1必须是某个对象的地址)

下面通过代码逐个展示使用方法:
全局函数、静态全局函数 √

static void show(const std::string& a, const std::string& b, const std::string& c)
{
	std::cout << a << "; " << b << "; " << c << std::endl;
}

int main()
{
	using namespace std::placeholders; // 由于std::placeholders,可以将参数传递给绑定函数的顺序更改

	auto x = bind(&show, _1, _2, _3);
	auto y = bind(&show, _3, _1, _2);
	auto z = bind(&show, "hello", _2, _1);

	auto xx = bind(&show, _3, _3, _3);

	x("one", "two", "three");  // one; two; three
	y("one", "two", "three");  // three; one; two
	z("one", "two");           // hello; two; one

	xx("one", "two", "three"); // three; three; three
}

类的static成员函数√
类的static成员函数不属于类对象,它属于整个类,并且static成员函数没有隐含的第一个this参数
结论:与①相比,对类的static成员函数bind时,只需要加上作用域A::,其他的都一样

class A{
public:
	static void show(const std::string& a, const std::string& b, const std::string& c)
	{
		std::cout << a << "; " << b << "; " << c << std::endl;
	}
};

int main()
{
	using namespace std::placeholders; // 由于std::placeholders,可以将参数传递给绑定函数的顺序更改

	auto x = bind(&A::show, _1, _2, _3);
	auto y = bind(&A::show, _3, _1, _2);
	auto z = bind(&A::show, "hello", _2, _1);

	auto xx = bind(&A::show, _3, _3, _3);

	x("one", "two", "three"); // one; two; three
	y("one", "two", "three"); // three; one; two
	z("one", "two");          // hello; two; one

	xx("one", "two", "three");// three; three; three

	return 0;
}

类的非static成员函数(注意:_1必须是某个对象的地址)

类的非static成员函数属于类对象,它第一个参数是隐含的,即指向自身的指针this
结论: 对类的非static成员函数bind时,除了需要加上作用域A::之外,还要多加一个类对象参数

class A{
public:
	void show(const std::string& a, const std::string& b, const std::string& c)
	{
		std::cout << a << "; " << b << "; " << c << std::endl;
	}
};

int main()
{
	using namespace std::placeholders; // 由于std::placeholders,可以将参数传递给绑定函数的顺序更改

	A aa;
	auto x = bind(&A::show, aa, _1, _2, _3);  //多加一个类对象
	auto y = bind(&A::show, aa, _3, _1, _2);
	auto z = bind(&A::show, aa, "hello", _2, _1);

	auto xx = bind(&A::show, aa, _3, _3, _3);

	x("one", "two", "three"); // one; two; three
	y("one", "two", "three"); // three; one; two
	z("one", "two");          // hello; two; one

	xx("one", "two", "three");// three; three; three

	return 0;
}

函数对象 / 仿函数- STL的仿函数、std::function √

#include <iostream>
#include <vector>
#include <algorithm>   //for count_if
#include <functional>  // for std::bind

using namespace std;
using namespace std::placeholders;

int main()
{
	vector<int> v{ 15, 37, 94, 50, 73, 58, 28, 98 };

	//通过bind2nd绑定仿函数less<int>()的第2参数为50
	int n = count_if(v.begin(), v.end(), not1(bind2nd(less<int>(), 50)));
	cout << "n = " << n << endl; //5(大于等于50的元素个数)

	//通过bind绑定仿函数less<int>()的第2参数为50
	cout << count_if(v.begin(), v.end(), bind(less<int>(), _1, 50)) << endl; //3

	//通过bind绑定
	//查找(50,73]之间的元素个数
	//            logical_and-逻辑与
	auto f = bind(logical_and<bool>(), bind(greater<int>(), _1, 50), bind(less_equal<int>(), _1, 73));
	cout << count_if(v.begin(), v.end(), f) << endl; //2

	return 0;
}

示例代码1

#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;

class Test{
public:
	typedef std::function<void(int, int)> pFUNC; //定义一个函数类型

	Test() :x_(0), y_(0){}
	Test(int x, int y, pFUNC pfunc) :x_(x), y_(y), pfunc_(pfunc){}
	void run(){
		pfunc_(x_, y_);
	}

	void showAll03(int x, int y, int z, int m, int n)
	{
		printf("%d,%d,%d,%d,%d\n", x, y, z, m, n);
	}
private:
	int x_, y_;
	pFUNC pfunc_;
};

void showAll01(int x, int y, int z){
	printf("%d,%d,%d\n", x, y, z);
}
void showAll02(int x, int y)
{
	printf("%d,%d\n", x, y);
}
int main(){
	int i, j;
	cout << "请输入i j :";
	cin >> i >> j;

	Test aa(i, j, std::bind(showAll01, 10, _1, _2)); //将showAll函数,适配成CallBack类型
	aa.run();

	Test bb(i, j, std::bind(showAll02, _1, _2));
	bb.run();

	Test dd;
	Test cc(i, j, std::bind(&Test::showAll03, &dd, 100, 200, _1, 300, _2));
	cc.run();
}

示例代码2

本案例不是使用面向对象的编程思想,而是使用基于接口的设计思想。

企鹅能游泳,也能跑,麻雀能飞,此时需要设计一个类,既能像企鹅那样会游泳、跑,也能像麻雀那样会飞。如果使用多继承(继承企鹅、麻雀),耦合的比较紧密,使用std::bind、std::function可以避免使用继承,是一种基于接口的设计思想。

在新类Foo中,
① 添加std::function成员变量
② 在Foo构造函数中,给成员变量赋值
③ 在main函数中,调用构造函数创建Foo对象,使用到bind

	Foo m_foo(
		bind(&Penguin::run, &peg),
		bind(&Penguin::swim, &peg),
		bind(&Sparrow::fly, &spr)
	);

全部代码:

#include <iostream>
#include <functional>
using namespace std;
using namespace std::placeholders;

//企鹅能游泳,也能跑
class Penguin
{
public:
	void run(){ cout << "run..." << endl; }
	void swim(){ cout << "swim..." << endl; }
};

//麻雀能飞
class Sparrow
{
public:
	void fly(){ cout << "fly..." << endl; }
};

// 一个既用到run,也用到fly的客户class
class Foo{
public:
	typedef std::function<void()> RUN;
	typedef std::function<void()> SWIM;
	typedef std::function<void()> FLY;

	Foo(RUN run, SWIM swim, FLY fly) :
		m_run(run), m_swim(swim), m_fly(fly)
	{ }


	void run()
	{
		m_run(); //调用回调函数
	}
	void swim()
	{
		m_swim();
	}
	void fly()
	{
		m_fly();
	}
private:
	RUN		m_run;
	SWIM	m_swim;
	FLY		m_fly;
};
int main()
{
	Penguin peg;
	Sparrow spr;

	Foo m_foo(
		bind(&Penguin::run, &peg),
		bind(&Penguin::swim, &peg),
		bind(&Sparrow::fly, &spr)
	);

	m_foo.run();
	m_foo.swim();
	m_foo.fly();

	return 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值