一、函数适配器简介
1、函数适配器概念
在 STL 中 预定义了很多 函数对象 , 如果要 对 函数对象 的 参数 / 返回值 进行 计算 或 设置 , 可以 使用 " 函数适配器 " 实现上述需求 ;
" 函数适配器 " 可以 将 已存在的 函数对象 转化为 另一种符合要求的 函数对象 ;
" 函数适配器 " 定义在 <functional> 头文件 中 ;
2、函数适配器分类
" 函数适配器 " 常用类型的两类 :
- 绑定适配器 :std::bind 绑定适配器 : 引入的一个 通用绑定机制 , 可 绑定 函数 / 函数指针 / 函数对象 / 成员函数指针 任意 位置 的 参数 到指定的值 , 也可以重新排列参数的顺序 , 或者将多个可调用对象组合在一起 ; C++ 11 最新引入的 , 建议使用 该 绑定适配器 ;
- std::binder1st 绑定适配器 : 将一个二元函数对象的 第一个 参数 绑定到一个特定的值 , 从而创建一个新的一元函数对象 ; C++ 11 弃用 , 建议使用 std::bind 绑定适配器 ;
- std::binder2nd 绑定适配器 : 将一个二元函数对象的 第二个 参数 绑定到一个特定的值 , 从而创建一个新的一元函数对象 ; C++ 11 弃用 , 建议使用 std::bind 绑定适配器 ;
- 组合适配器 :unary_negate 组合适配器 : 将 一元谓词 的返回值 , 进行 逻辑取反 操作 , 得到一个新的 bool 类型 布尔值 ;
- binary_negate 组合适配器 : 将 二元谓词 的返回值 , 进行 逻辑取反 操作 , 得到一个新的 bool 类型 布尔值 ;
3、函数适配器辅助函数
函数适配器 的 创建构造 需要很复杂的类型声明 , 为了方便开发 , C++ 的 STL 标准模板库 中提供了 " 函数适配器辅助函数 " , 可以 无需显示声明类型 , 就可以 实现 函数适配器 的创建 ;
常用的 " 函数适配器辅助函数 " :
- bind1st 函数 : 辅助构造 std::binder1st 绑定适配器 实例对象 , 可以 为 二元函数 第一个参数 绑定一个固定的值 ;
- bind2nd 函数 : 辅助构造 std::binder2nd 绑定适配器 实例对象 , 可以 为 二元函数 第二个参数 绑定一个固定的值 ;
- not1 函数 : 辅助构造 unary_negate 组合适配器 实例对象 , 将 一元谓词 的返回值 , 进行 逻辑取反 操作 ;
- not2 函数 : 辅助构造 unary_negate 组合适配器 实例对象 , 将 二元谓词 的返回值 , 进行 逻辑取反 操作 ;
二、函数适配器使用示例 - std::bind2nd 函数
1、std::bind2nd 函数原型
std::bind2nd 是一个函数适配器 , 它用于 生成一个新的一元函数对象 , 该对象将给定二元函数对象的第二个参数绑定到一个特定的值 ;
std::bind2nd 函数原型如下 :
template <class Operation>
binder2nd<Operation> bind2nd(const Operation& op, const typename Operation::second_argument_type& value);
- 参数解析 :
- Operation &op 参数 : 该参数是 要绑定的二元函数对象 , 它必须定义 second_argument_type 作为其第二个参数的类型 , 也就是说 第二个参数类型 需要 与 本函数的 value 值类型相同 ;
- value 参数 : 该参数是 要绑定到二元函数对象第二个参数的 值 或 变量 ;
- 返回值解析 : 返回一个 binder2nd 类 的对象 , 该对象是一个一元函数对象 , 可以像普通函数对象一样被调用 ;
2、代码示例 - std::bind2nd 函数
代码示例 :
#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"
int main() {
// 创建一个 set 集合容器
vector<int> myVector;
// 向容器中插入元素
myVector.push_back(9);
myVector.push_back(5);
myVector.push_back(2);
myVector.push_back(7);
myVector.push_back(2);
// 向 foreach 循环中传入 Lambda 表达式
for_each(myVector.begin(), myVector.end(), [](int a) {
std::cout << a << " ";
});
cout << endl;
// 计算 vector 容器中 , 值为 2 的个数
int equal_num = 2;
int count = count_if(myVector.begin(), myVector.end(), bind2nd(equal_to<int>(), equal_num));
cout << "值为 2 的元素个数 : " << count << endl;
// 控制台暂停 , 按任意键继续向后执行
system("pause");
return 0;
};
执行结果 :
9 5 2 7 2
值为 2 的元素个数 : 2
Press any key to continue . . .
三、函数适配器使用示例 - std::bind 函数
1、std::bind 函数原型
std::bind 函数适配器 是 C++11 新引入的 函数适配器 , 可以 将 函数 / 函数对象 / 函数指针 与 其参数绑定到一起 , 产生一个新的可调用函数对象 ;
std::bind 函数适配器 比 std::bind1st 和 std::bind2nd 函数适配器更加灵活 ,
- std::bind1st 函数适配器 只能绑定 函数对象 第一个函数参数 ;
- std::bind2nd 函数适配器 只能绑定 函数对象 第二个函数参数 ;
- std::bind 函数适配器 不仅能绑定 第一第二个函数参数 , 还能绑定第三个第四个直至第 N 个函数参数 , 没有任何位置限制 ;
std::bind 函数原型如下 :
template< class Fn, class... Args >
/*unspecified*/ bind( Fn&& fn, Args&&... args );
- 参数解析 :
- Fn&& fn 参数 : fn 是一个可调用对象 , 可以是 函数 / 函数指针 / 成员函数 / 成员函数指针 / 函数对象 / 谓词 等可调用对象 ;
- Args&&… args 参数 : 这是一个可变的参数 , 参数可以是值 , 引用 或者 占位符 ;
- 返回值解析 : 返回的是一个未指定的类型 , 这个类型是一个函数对象 , 可以像普通函数那样被调用 ; 当返回的函数对象被调用时 , 它会用提供的参数和 std::bind 中的占位符来调用 fn ;
占位符 是 std::placeholders::_1 , std::placeholders::_2 等值 ;
如果 参数中是 std::placeholders::_1 占位符 , 表示 第一个 参数 , 不进行修改 , 仍然保持其默认值 ; std::placeholders::_2 占位符 , 表示 第二个 参数 , 不进行修改 , 仍然保持其默认值 ;
2、代码示例 - std::bind 函数
代码示例 :
#include "iostream"
using namespace std;
#include <vector>
#include <algorithm>
#include "functional"
int main() {
// 创建一个 set 集合容器
vector<int> myVector;
// 向容器中插入元素
myVector.push_back(9);
myVector.push_back(5);
myVector.push_back(2);
myVector.push_back(7);
myVector.push_back(2);
// 向 foreach 循环中传入 Lambda 表达式
for_each(myVector.begin(), myVector.end(), [](int a) {
std::cout << a << " ";
});
cout << endl;
// 计算 vector 容器中 , 值为 2 的个数
int equal_num = 2;
int count = count_if(myVector.begin(), myVector.end(), bind(equal_to<int>(), placeholders::_1, equal_num));
cout << "值为 2 的元素个数 : " << count << endl;
// 控制台暂停 , 按任意键继续向后执行
system("pause");
return 0;
};
执行结果 :
9 5 2 7 2
值为 2 的元素个数 : 2
Press any key to continue . . .