-
bind1st和bind2d是STL中的;
-
bind1st和bind2d作用: 将二元函数对象的一个参数绑定,使其变为一元函数对象;
-
缺点: 只能用于二元函数对象。
-
函数对象: 对象拥有小括号重载函数的对象。
#include例1—改变排序顺序--包含c++库中的所有的函数对象 #include --包含了c++库中的所有的泛型算法
greater是一个二元函数对象:(因为一次需要从容器中拿2个函数对象出来)
传入greater函数对象后,就是从大到小进行排序了。
#include例2—将70按顺序插入到vec容器中#include #include #include #include using namespace std; template void showContainer(Container& con) { typename Container::iterator it = con.begin(); //编译器是从上到下编译的,这个还没有实例化,它不知道这个名字作用域后面的iterator是类型还是变量 //typename告知编译器后面类型的作用域后面是类型 for (; it != con.end(); ++it) { cout << *it << " "; } cout << endl; } int main() { vector 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 ());//大到小排序 showContainer(vec); return 0; }
问题:将70按顺序插入到vec容器中
使用find_if函数需要传入一个一元函数对象(一次从容器中拿出一个元素和70进行比较 )
注意:库里面提供的函数对象都是二元的,没有办法直接使用;怎么办?
使用绑定器; 将二元函数对象转换为一元函数对象;
使用greater函数对象,用绑定器将其绑定为一元函数对象:
bind1st:绑定第1个参数,也就是70 > b,b就是容器中的每个元素,找到第一个小于70的位置。
使用less函数对象,用绑定器将其绑定为一元函数对象:
bind2d:绑定第2个参数,a < 70,找到第一个小于70的位置。
注意,这是生成的随机数
实现自己的find_if—my_find_if
函数模板,接收用户传入的二元函数对象和所要绑定的值;
为什么用函数模板去封装?
不用自己去写模板参数,可以自己推导。
mybind1st就是将函数对象封装了一下。
测试:
直接使用自己的即可。
bind2d就是在类中重载时,将绑定的位置交换即可。
#include1.3、function函数对象类型的应用示例#include #include #include #include using namespace std; template void showContainer(Container& con) { typename Container::iterator it = con.begin(); for (; it != con.end(); ++it) { cout << *it << " "; } cout << endl; } template Iterator my_find_if(Iterator first, Iterator last, Compare comp) //遍历这2个迭代器之间的元素,如果满足函数对象的运算,就返回当前迭代器,如果都不满足,返回end() { for (; first != last; ++first) { if (comp(*first))//comp.operator()(*first)一元函数对象,因为要从容器拿1个元素和它指定的元素比较 //my_find_if需要1元函数对象,而在库里面都是二元的 { return first; } } return last; } template class _mybind1st//绑定器是函数对象的一个应用 { public: _mybind1st(Compare comp, T val) :_comp(comp), _val(val) {} bool operator()(const T& second) { return _comp(_val, second);//greater } private: Compare _comp; T _val; }; //mybind1st(greater (), 70) template _mybind1st mybind1st(Compare comp, const T& val) { //直接使用函数模板,好处是,可以进行类型的推演 return _mybind1st (comp, val); } int main() { vector 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 ());//大到小排序 showContainer(vec); auto it1 = my_find_if(vec.begin(), vec.end(), mybind1st(greater (), 70)); //auto it1 = my_find_if(vec.begin(), vec.end(),bind2nd(less (), 70)); if (it1 != vec.end()) { vec.insert(it1, 70); } showContainer(vec); return 0; }
function:函数对象类;
- 绑定器、函数对象、lambda表达式实际上都是函数对象。
- 如果我们最终得到的绑定器、函数对象、lambda表达式,这些函数对象,想在多条语句中应用 ,怎么办?如何将这些函数对象的类型留下来?
源码中希望你用一个函数类型来实例化function模板。
区别函数类型和函数指针类型:
函数指针类型:
- 是一个指针类型,指向返回值是void,不带形参的函数。
函数类型:
- 我们需要用函数类型来实例化function。
- 只给出返回值和参数列表即可
无参的hello1函数:
用函数对象类型func1将hello1函数类型保留下来了,然后就可以使用func1()调用了。
测试结果:
对于有参的hello2函数:
运行结果:
sum函数:
运行结果:
上面说明,function非常好用,可以直接将函数类型留下来。
function不仅仅可以留下函数类型,也可以留下函数对象类型。(函数对象的本质是()重载函数)
也可以说function是对一个函数/函数对象的包装。
结果:
上面是对function作用于全局函数,将其函数类型留下来。
当然,function也可以将类的成员方法留下来!
成员方法的调用必须依赖一个对象。
在调用时,第一个参数对应传入一个临时对象即可。
小结:
funtion的作用:
- 保留 全局函数、成员函数、其他函数对象的类型,然后再各处都可以使用。
我们使用function,将函数的类型保存下来使用
问题:这里也可以用函数指针来接收函数的类型吗?
- 可以接收函数类型;但是只能接收普通的函数,不能接收绑定器绑定的函数对象,也不能接收lambda表达式函数对象。
#include1.4、模板的完全特例化和非完全特例化#include #include
模板的完全特例化有完全特例化,就选择对应的完全特例化,有部分特例化,就匹配部分特例化,没有的话,就原模板实例化
能运用在int类型上,字符串比较就不行了。
此时的实例化compare代码就不行了,字符串比较的是地址,并不是字典的顺序。
需要多加一个模板的完全特例化:(完全特例化: 类型完全是已知的)
- template后面的<>什么参数都没有,表示参数都是已知的。
运行结果:
原模板实例化:
完全特例化版本:
- template后面的<>什么参数都没有,表示参数都是已知的。
部分特例化版本: - vector后面知道它是一个指针类型,但不知道具体什么指针,template后面的<>指针类型。
函数指针的部分特例化:
函数类型的部分特例化:
区分函数类型和函数指针类型:
运行结果:
#include模板的实参推演#include using namespace std; template class Vector { public: Vector() { cout << "call Vector template init" << endl; } }; //下面这个是对char*类型提供的完全特例化版本 #1 template<>//特例化的语法 class Vector { public: Vector() { cout << "call Vector init" << endl; } }; //下面这个是对指针类a型提供的部分特例化版本 #2 template class Vector { public: Vector() { cout << "call Vector init" << endl; } }; //指针函数指针(有返回值,有两个形参变量)提供的部分特例化 template class Vector { public: Vector() { cout << "call Vector init" << endl; } }; //针对函数(有一个返回值,有两个形参变量)类型提供的部分特例化 template class Vector { public: Vector() { cout << "call Vector init" << endl; } }; int sum(int a, int b) { return a + b; } int main() { Vector vec1; Vector vec2; Vector vec3; Vector vec4; Vector vec5;//function //注意区分一下函数类型和函数指针类型 //用函数指针定义的变量本身就是一个指针 typedef int(*PFUNC1)(int, int); //PFUNC1是函数指针类型 PFUNC1 pfunc1 = sum; cout << pfunc1(10, 20) << endl; typedef int PFUNC2(int, int); //PFUNC2是函数指针 //函数类型在定义的时候,需要将指针*加上 PFUNC2* pfunc2 = sum; cout << (*pfunc2)(10, 20) << endl; return 0; }
程序中添加一个sum函数;
程序推导出:
问题: 上面直接退的函数类型,范围太大了,有返回值类型,还有形参,我们想将返回值和所有形参的类型都取出来;
我们直接用一个函数指针的模板部分特例化来做:
我们就可以得到细分的类型。
定义一个Test类,里面有一个成员函数sum。
得到一个指向成员方法的函数指针类型。
我们将其参数细分,添加func3函数
我们直接用一个成员方法函数指针的模板部分特例化来做:
#include总结#include using namespace std; int sum(int a, int b) { return a + b; } //T包含了所有的大的类型 返回值,所有形参的类型都取出来 template void func(T a) { cout << typeid(T).name() << endl; } template void func2(R(*a)(A1, A2)) { cout << typeid(R).name() << endl; cout << typeid(A1).name() << endl; cout << typeid(A2).name() << endl; } class Test { public: int sum(int a, int b) { return a + b; } }; template void func3(R(T::* a)(A1, A2)) { cout << typeid(R).name() << endl; cout << typeid(T).name() << endl; cout << typeid(A1).name() << endl; cout << typeid(A2).name() << endl; } int main() { func(10); func("aaa"); func(sum);//T int (*)(int,int) int (int,int) func2(sum); func(&Test::sum);//int (__thiscall Test::*)(int,int) func3(&Test::sum); return 0; }
- 这几个例子指导我们在写函数模板,类模板时,针对一个具体情况,把他们一个大类型的细分类型,定义相应的参数,接收大类型的所有细分类型,使用的就是模板部分偏特化。



