STL 函数对象适配器

函数对象适配器主要用于对函数、函数对象进行适配(转换),使得原本不符合接口需求的函数、函数对象变得符合要求。比如:我们有一个 2 个参数的函数对象,但是我们需要 1 个参数的函数对象,此时可以通过函数对象适配器进行转换。

  1. 绑定适配器: bind1st、bind2nd、bind
  2. 成员函数适配器: mem_fun_ref、mem_fun
  3. 取反适配器: not1、not2
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

1. 绑定适配器

bind1st、 bind2nd 作用就是将两个参数的函数对象转换为一个参数的函数对象。
bind1st 会将某一个值赋值给第一个参数,剩下一个参数由 for_each 传递
bind2nd 会将某一个值赋值给第二个参数,剩下一个参数由 for_each 传递

绑定适配器在使用的时候,要求如下:
1. 被适配的函数对象要继承一个类:如果是两个参数函数对象需要继承:binary_function, 如果是一个参数需要继承:unary_function
2. 将重载的 operator() 函数指定为常函数

注意:bind1st、bind2nd 不能对普通函数进行适配;如果有超过两个参数的函数对象,bind1st、bind2nd 无法适配。

// binary_function<参数类型, 参数类型, 返回值类型>
struct MyFunctor : public binary_function<int, int, void>  
{
	void operator()(const int& v1, const int& v2) const
	{
		cout << v1 << " " << v2 << endl;
	}
};

void test01()
{
	vector<int> v = { 10, 20, 30, 40, 50 };
	// 函数调用之后,会返回一个参数的函数对象,其中一个值就是固定的100
	// bind1st(MyFunctor2(), 100) 
	for_each(v.begin(), v.end(), bind1st(MyFunctor(), 100));
	for_each(v.begin(), v.end(), bind2nd(MyFunctor(), 100));
}

bind 比 bind1st 和 bind2nd 适用的场景更广,既可以适配普通函数、也可以适配函数对象,也可以适配多个参数的普通函数、函数对象。从左向右的顺序依次绑定值,不绑定的参数使用占位符代替。如下代码所示:

struct MyFunctor3
{
	void operator()(const int& v1, const int& v2, const int& v3) const
	{
		cout << v1 << " " << v2 << " " << v3 << endl;
	}
};


void print(int v1, int v2)
{
	cout << v1 << " " << v2 << endl;
}

void test02()
{
	// 从左向右的顺序依次绑定值,不绑定的参数使用占位符代替
	auto func1 = bind(MyFunctor3(), 100, placeholders::_1, 200);
	func1(1000);

	auto func2 = bind(MyFunctor3(), placeholders::_1, placeholders::_2, 300);
	func2(1000, 2000);

	auto func3 = bind(print, placeholders::_1, 200);
	func3(666);
}

2. 成员函数适配器

该适配器使用场景针对的是容器中的元素是对象引用、对象指针,通过成员函数适配器使得容器中的对象调用其成员函数。

class Person
{
public:
	Person(string name, int age) : m_name(name), m_age(age) {}
	void show()
	{
		cout << m_name << " " << m_age << endl;
	}
public:
	string m_name;
	int m_age;
};

// mem_fun_ref、mem_fun
void test03()
{
	// 容器中存储的是对象
	vector<Person> v = { Person("aaa", 10), 
						 Person("bbb", 20) , 
						 Person("ccc", 30) };
						 
	// 希望遍历容器中对象元素时候,调用对象的某个成员函数
	// 如果容器中存储的是对象实体,那么使用 mem_fun_ref 进行成员函数适配
	// 注意:成员函数不能有参数
	for_each(v.begin(), v.end(), mem_fun_ref(&Person::show));

	// mem_fun 用于容器中存储的是对象指针
	vector<Person*> v1 = { new Person("aaa", 10), 
						   new Person("bbb", 20) , 
						   new Person("ccc", 30) };
	for_each(v1.begin(), v1.end(), mem_fun(&Person::show));
}

3. 取反适配器

对返回值为 bool 类型的函数对象取反操作
1. not1 针对返回值是 bool, 参数只有一个的函数对象
2. not2 针对返回值是 bool, 参数有两个的函数对象

struct MyCondition1 : public unary_function<int, bool>
{
	bool operator()(const int& v) const
	{
		return v > 2;
	}
};

void test04()
{
	vector<int> v = { 9, 2, 4, 3, 1, 2, 6, 2 };
	// 统计容器中元素大于 2 的个数
	cout << count_if(v.begin(), v.end(), MyCondition1()) << endl;
	// 统计容器中元素不大于2个数
	cout << count_if(v.begin(), v.end(), not1(MyCondition1())) << endl;


	vector<int> v1 = { 2, 4, 5, 6, 8, 1 };
	vector<int> v2 = { 1, 3, 5, 7, 8, 1 };

	// 返回两个容器中第一组不相等的元素,并返回两个迭代器
	// auto it = mismatch(v1.begin(), v1.end(), v2.begin(), equal_to<int>());
	// cout << *it.first << " " << *it.second << endl;
	
	
	// 返回两个容器中第一组相等的元素,并返回两个迭代器
	auto it = mismatch(v1.begin(), v1.end(), v2.begin(), not2(equal_to<int>()));
	cout << *it.first << " " << *it.second << endl;

}
未经允许不得转载:一亩三分地 » STL 函数对象适配器
评论 (0)

6 + 6 =