今天我们先来谈谈C++ 标准库里面的绑定器bind1st
,bind2nd
和函数对象function
C++ 绑定器和函数对象
- 一、绑定器
- 二、函数对象
一、绑定器
虽然在C++11标准中这两个绑定函数已经被弃用,但仍然值得我们深入思考其底层原理。从字面上理解,“绑定” 这两个字表明它可能将某个类型或值直接关联到了某个特定的 “位置” 上,其定义可以被概括为:
-
🐶bind1st函数接受一个二元函数和一个值,返回一个新的函数对象,该函数对象将被绑定到二元函数的第一个参数上。这意味着第二个参数可以在调用时提供,而第一个参数是预先绑定的。
-
🐱bind2nd函数接受一个二元函数和一个值,返回一个新的函数对象,该函数对象将被绑定到二元函数的第二个参数上。这意味着第一个参数可以在调用时提供,而第二个参数是预先绑定的。
简而言之,bind1st
把函数对象 operator()
重载函数的第一个形参变量绑定成一个确定的值,而bind2nd
函数则是把第二个形参变量绑定成一个确定的值。下面我们给出一个简单的示例来加深理解:
#include<iostream>
#include<functional>
#include<vector>
using namespace std;template<typename T>
void show_all(T& val) //通用函数模板,用来输出所有元素
{typename T::iterator it = val.begin();while (it != val.end()){cout << *it << " "; it++;}
}int main()
{srand(time(NULL));vector<int> v;for (int i = 0; i < 20; i++)v.push_back(rand() % 100);//v.push_back(rand() % 100 + 50); 一定找不到// 使用 bind1st(greater<int>(), 50) 查找第一个大于50的元素auto it = find_if(v.begin(), v.end(), bind1st(greater<int>(), 50));//auto it = find_if(v.begin(), v.end(), bind2nd(less<int>(), 50));if (it != v.end()){v.insert(v.end(), 50);}show_all(v);return 0;
}
通过思考🤔🤔🤔,我们可以发现find_if
查询的条件是基于它的第三个参数bind1st
中的(greater<int>(), 50)
,我们看greater
的底层源码可以知道,50
实际上是替换了下图中的_Left
,而从 v.begin() 到 v.end() 遍历到的元素将直接作为_Right
传入,以此来判断是否有小于 50 的元素
同理,如果使用bind2nd
,我们将greater<int>()
改为 less<int>()
能够得到同样的结果,这里就不在赘述了。下面我们自己来写写它们的简单底层实现(自用):
- 自定义查找函数
my_find_if
:
template<typename Iterator, typename Compare>
Iterator my_find_if(Iterator first, Iterator last, Compare comp)
{while (first != last){if (comp(*first)) return first;first++;}return last;
}
通过模板参数 Iterator
接受任意迭代器类型,Compare
接受任意比较函数对象类型。在给定范围 [first, last)
内查找满足条件的第一个元素。循环遍历范围,使用传入的比较函数对象 comp
判断是否满足条件。如果找到满足条件的元素,返回该元素的迭代器;否则,返回 last。
- 一元函数对象
_Mybind1st
及其辅助函数My_bind1st
:
template<typename Compare, typename T>
class _Mybind1st
{
public:_Mybind1st(Compare comp, T val): _comp(comp), _val(val){}bool operator()(const T& second) //传入容器里的所有元素{ return _comp(_val, second);// my_bind2nd(second, _val);}
private:Compare _comp;T _val;};template<typename Compare, typename T>
_Mybind1st<Compare, T> My_bind1st(Compare comp, const T& val)
{return _Mybind1st<Compare, T>(comp, val);
}
定义了一个一元函数对象 _Mybind1st
,用于在比较中固定第一个参数。_Mybind1st
类接受一个比较函数对象和一个固定值,通过 operator()
实现比较。辅助函数 My_bind1st
用于创建 _Mybind1st
类的实例,将比较函数对象和固定值传递给构造函数。
最后总结一句: 绑定器 + 二元函数对象 =》 一元函数对象
二、函数对象
函数对象是一个具有函数调用运算符(operator())的类对象。它可以像普通函数一样被调用,并且可以保存内部状态。函数对象可以用作参数传递给其他函数,也可以在算法中使用。在C++中,函数对象可以通过重载函数调用运算符来实现。函数调用运算符是一个特殊的成员函数,它没有函数名,只有一个参数列表和一个返回类型。当使用函数对象调用时,实际上就是调用了该运算符重载函数,相关代码如下:
#include<iostream>
#include<functional>
#include<string>
using namespace std;void hello1() { cout << "null" << endl;
}void hello2(string str) { cout << str << endl;
}int sum(int a, int b) { return a + b;
}// 自定义的函数模板类
template<typename Fty>
class my_function {};// 部分特例化,用于处理函数指针
template<typename R, typename ...A>
class my_function<R(A...)>
{
public:// 函数指针类型using PFUNC = R(*)(A...);// 构造函数接受函数指针作为参数my_function(PFUNC pfunc) : _pfunc(pfunc) {}// 重载函数调用运算符,以调用函数指针R operator()(A ... arg){return _pfunc(arg ...);}private:PFUNC _pfunc; // 存储函数指针
};class Test
{
public:void hello(string str) { cout << str << endl; }
};int main()
{// 使用标准库的functionfunction<void()> f1 = hello1;f1();function<void(string)> f2 = hello2;f2("hello");// 使用lambda表达式function<int(int, int)> f3 = [](int a, int b)->int {return a + b; };cout << f3(9, 9) << endl;// 以下两行被注释掉,因为需要修改成正确的方式处理成员函数指针// function<void(Test*, string)> f4 = &Test::hello;// f4(&Test(), "Test");// 使用自定义的my_function,包装普通函数my_function<int(int, int)> f5(sum);cout << f5(9, 9) << endl;// 使用自定义的my_function,包装函数对象my_function<void(string)> f6 = hello2;f6("my_hello2");return 0;
}
这里就不解释了,仅作为理解而已。
🌻🌻🌻以上就是有浅谈C++绑定器bind1st、bind2nd和函数对象function的相关内容,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻