文章目录
- What什么是?
- How什么时候用?如何用?
- bind1st和bind2nd的底层实现原理
- my_find_if分析
- myBind1st分析
What什么是?
bind1st 和bind2nd分别是一个用来绑定函数对象的第一个参数或第二个参数的适配器。它在 C++98 和 C++03 标准中很常用,但从 C++11 开始,这个功能已经被认为是过时的(deprecated),并在后续的 C++17 标准中被完全移除。
作用就是:
绑定器 + 二元函数对象 ==> 一元函数对象
他俩只能应用于二元函数对象
How什么时候用?如何用?
下叙函数的代码流程为:
定义一个模板函数showContainer
来打印任意类型的容器;
随机生成一个数组;
我们对其进行排序,首先使用默认排序less
;随后使用重载的sort
函数,丙通过greater
从大到小排序;(其中less
和greater
都是二元谓词)
我们现在有一个需求:
把70按顺序插入到vec容器当中 找第一个小于70的数字
很明显我们现在只需要一个一元谓词,但是greater和less都是二元谓词,这怎么办呢?使用绑定器!
绑定器的作用就是:
绑定器 + 二元函数对象 ==> 一元函数对象
//略去了头文件和命名空间的导入
//...
template<typename Container>
void showContainer(Container &con) {
typename Container::iterator it = con.begin();
for (; it != con.end(); ++it) {
cout << *it << " ";
}
cout << endl;
}
int main () {
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20; ++i) {
vec.push_back(rand() % 100 + 1);
}
showContainer(vec);
sort(vec.begin(), vec.end()); //默认递增排序
showContainer(vec);
//greater是一个二元函数对象,从大到小排序
sort(vec.begin(), vec.end(), greater<int>());
showContainer(vec);
/*
把70按顺序插入到vec容器当中 找第一个小于70的数字
需要一个一元函数对象,也就是operator()(const T &val)
greater a > b
less a < b
绑定器 + 二元函数对象 ==> 一元函数对象
bind1st: + greater bool operator()(70, const _Tp& __y) const
bind2nd: + less bool operator()(const _Tp& __x, 70) const
*/
//auto it1 = find_if(vec.begin(), vec.end(),
//bind1st(greater<int>(), 70));
auto it1 = find_if(vec.begin(), vec.end(),
bind2st(less<int>(), 70));
if (it1 != vec.end()) {
vec.insert(it1, 70);
showContainer(vec);
}
}
bind1st和bind2nd的底层实现原理
我们这里首先实现STL标准库中的算法find_if
为my_find_if
;
然后实现myBind1st
main函数结构如下:
int main () {
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20; ++i) {
vec.push_back(rand() % 100 + 1);
}
showContainer(vec);
//greater是一个二元函数对象,从大到小排序
sort(vec.begin(), vec.end(), greater<int>());
showContainer(vec);
auto it1 = my_find_if(vec.begin(), vec.end(),
myBind1st(greater<int>(), 70));
//auto it1 = my_find_if(vec.begin(), vec.end(),
//bind2st(less<int>(), 70));
if (it1 != vec.end()) {
vec.insert(it1, 70);
showContainer(vec);
}
return 0;
}
my_find_if分析
从
auto it1 = my_find_if(vec.begin(), vec.end(),
myBind1st(greater<int>(), 70));
在STL标准库的find_if
,可以看到返回类型是一个迭代器类型,传参是容器的开始和结束位置的迭代器,最后传入的是一个一元谓词。查找的流程就是遍历指定的范围,碰到符合条件的即返回。
template<typename Iterator, typename Compare>
Iterator my_find_if(Iterator first, Iterator last, Compare cmp) {
for (; first != last; ++first) {
if (cmp(*first)) { //cmp.operator() (*first)小括号运算符重载
return first;
}
}
return last;
}
myBind1st分析
首先我们要搞清楚bind1st的传参和返回值:
bind1st(greater<int>(), 70)
传入的是一个二元函数对象和具体的数值,返回值其实就是一个一元函数对象,所以我们可以模拟出:
// myBind1st(greater<int>(), 70))
template<typename Compare, typename T>
_mybind1st<Compare, T> myBind1st (Compare cmp, const T &val) {
// 直接使用函数模板,好处是可以进行类型的推演
return _mybind1st<Compare, T>(cmp, val);
}
我们再来实现这个_mybind1st:
template<typename Compare, typename T>
class _mybind1st { //绑定器是函数对象的一个应用
public:
_mybind1st(Compare cmp, T val)
:_cmp(cmp), _val(val)
{}
bool operator() (const T &second) { //重载函数调用运算符
return _cmp(_val, second);
}
private:
Compare _cmp;
T _val;
};
这样我们就可以愉快得使用啦