3.2 根据transform源码实现函数对象
根据源码分析,回调函数接口应为二元函数对象,函数返回值为一个元素,代码如下:
1. template<typename _MyType> 2. class _TransformClass 3. { 4. public: 5. _MyType operator()(_MyType& t1, _MyType& t2) 6. { 7. return (t1 + t2); 8. } 9. }; 10. 11. template<typename _MyType> 12. _MyType _TransformFunc(_MyType& t1, _MyType& t2) 13. { 14. return (t1 + t2); 15. }
继续在主函数添加测试代码如下:
1. vector<string> v3(for_each_obj.get_count() + 1); 2. v3[6] = "end"; 3. transform(v1.begin(), v1.end(), v1.begin(), v3.begin(), _TransformClass<string>()); 4. for_each(v3.begin(), v3.end(), _FroEachClass<string>()); 5. cout << endl; 6. vector<string>::iterator it = transform(v1.begin(), v1.end(), v1.begin(), v3.begin(), _TransformFunc<string>); 7. for_each(v3.begin(), v3.end(), _FroEachClass<string>()); 8. cout << endl; 9. cout << *it << endl; //transform 返回的是: v1 + v2 最后一个元素相加后,后面的那个位置的迭代器
编译运行
通过输出结果看到,已经实现了把容器1和2相加存入第三个容器的功能。我们在源码分析中说到,transform返回容器3的输出迭代器,那么返回的迭代器位置究竟在哪呢,我们在程序进行了测试,也就是这几句程序
1. vector<string>::iterator it = transform(v1.begin(), v1.end(), v1.begin(), v3.begin(), _TransformFunc<string>); 2. for_each(v3.begin(), v3.end(), _FroEachClass<string>()); 3. cout << endl; 4. cout << *it << endl; //transform 返回的是: v1 + v2 最后一个元素相加后,后面的那个位置的迭代器
通过对返回的迭代器指向的内容打印可以得出结论,transform算法返回的是v1.end()减去v1.begin()后面的一个位置,加入容器v1有6个元素,那么transform返回的应该是v3的第7个位置,具体可见程序中的说明。
4. sort算法与二元谓词
本节目标是通过sort算法实现排序功能。
4.1 sort算法源码分析
源码如下:
1. template <class _RanIt, class _Pr> 2. void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last), using _Pred 3. _Adl_verify_range(_First, _Last); 4. const auto _UFirst = _Get_unwrapped(_First); 5. const auto _ULast = _Get_unwrapped(_Last); 6. _Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred)); 7. }
1. template <class _RanIt, class _Pr> 2. void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) { 3. // order [_First, _Last), using _Pred 4. _Iter_diff_t<_RanIt> _Count; 5. while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal) { // divide and conquer by quicksort 6. auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred); 7. // TRANSITION, VSO#433486 8. _Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions 9. 10. if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half 11. _Sort_unchecked(_First, _Mid.first, _Ideal, _Pred); 12. _First = _Mid.second; 13. } else { // loop on first half 14. _Sort_unchecked(_Mid.second, _Last, _Ideal, _Pred); 15. _Last = _Mid.first; 16. } 17. } 18. 19. if (_ISORT_MAX < _Count) { // heap sort if too many divisions 20. _Make_heap_unchecked(_First, _Last, _Pred); 21. _Sort_heap_unchecked(_First, _Last, _Pred); 22. } else if (2 <= _Count) { 23. _Insertion_sort_unchecked(_First, _Last, _Pred); // small 24. } 25. }
首先分析源码,sort算法实现的是排序功能,我们可以按自己的排序规则进行排序,比如对一个people类按照成员变量年龄进行排序,一个成绩管理系统,按照成绩排序等,另外STL还提供了预定义函数对象供我们使用,比如less、greater等。sort算法接收的是一个二元谓词。
4.2 根据sort源码实现二元谓词
我们实现从大到小排序,代码如下:
1. //二元谓词 2. template<typename _MyType> 3. class _SortClass 4. { 5. public: 6. bool operator()(_MyType& t1, _MyType& t2) 7. { 8. return (t1 > t2); 9. } 10. }; 11. 12. template<typename _MyType> 13. bool _SortFunc(_MyType& t1, _MyType& t2) 14. { 15. return (t1 > t2); 16. }
在主函数添加如下测试代码:
1. v4.push_back(1); 2. sort(v4.begin(), v4.end(), _SortClass<int>()); 3. for_each(v4.begin(), v4.end(), _FroEachClass<int>()); 4. cout << endl; 5. sort(v4.begin(), v4.end(), _SortFunc<int>); 6. for_each(v4.begin(), v4.end(), _FroEachClass<int>()); 7. cout << endl;
编译运行
我们还可以使用预定义函数对象实现从大到小排序
1. sort(v4.begin(), v4.end(), greater<int>()); //使用预定义函数对象 2. for_each(v4.begin(), v4.end(), _FroEachClass<int>()); 3. cout << endl;
通过自定义的谓词,我们可以实现自己的数据类型的排序,这就是sort算法为我们提供的统一个排序模型。
5. 函数适配器
有时候算法中的函数对象只接收一元函数对象,但是我们想要实现的功能需要二元函数对象完成,这时我们就可以通过绑定器把一个二元函数对象和一个参数绑定在一起,适配成一元函数对象。比如,我们要用count_if实现计算int型容器中大于5的元素的个数,我们可以借用预定义函数对象greater,但是greater是一个二元谓词,我们在第二节分析过count_if源码,count_if接收的是一个一元函数对象,这时我们就可以使用绑定器bind2nd把元素5绑定到greater的第二个参数位置,把他适配为一元函数对象。
在主函数添加如下测试代码:
1. int n = 5; 2. int num = count_if(v4.begin(), v4.end(), bind2nd(greater<int>(), n)); 3. //count_if 接收一元函数对象或一元谓词,我们借用二元谓词greater实现计算大于5的元素个数 4. //这时可以使用绑定器 bind2nd 把预定义函数对象greater和一个参数n适配为一元谓词 5. cout << "greater " << n << " : " << num << endl;
编译运行
大于5的个数为5,结果正确。
通过这个例子我们可以再一次体会到STL算法为我们提供的统一性,我们使用count_if算法完成了两个自己的算法,一个是计算容器中某元素的个数,一个是计算容器中大于某元素的个数。只要是我们的回到调函数功能和参数模型能匹配算法提供的模型,就可以套用该算法,这就是统一性。




