函数对象适配器主要用于对函数、函数对象进行适配(转换),使得原本不符合接口需求的函数、函数对象变得符合要求。比如:我们有一个 2 个参数的函数对象,但是我们需要 1 个参数的函数对象,此时可以通过函数对象适配器进行转换。
- 绑定适配器: bind1st、bind2nd、bind
- 成员函数适配器: mem_fun_ref、mem_fun
- 取反适配器: 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; }