探秘C++仿函数

最近喵哥遇到一个问题:如何在不借助额外空间(新建vector等)来实现map自己的想法(不只是表面的升序、降序)排序(sort只适用于顺序容器,map并不可以使用)。

如果忽略“不借助额外空间这个要求”,完全可以用一个vector来实现:

#include <iostream>
#include <map>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <list>

bool secSort(pair<string, int> const x, pair<string, int> const y) {
	return x.second > y.second;
}

int main()
{

	map<string, int> name_score_map;
	name_score_map["LiMin"] = 90;
	name_score_map["ZiLinMi"] = 79;
	name_score_map["BoB"] = 92;
	name_score_map.insert(make_pair("Bing", 99));
	name_score_map.insert(make_pair("Albert", 86));
	//借助vector实现map按照second排序
	vector<pair<string, int>> vecm(name_score_map.begin(), name_score_map.end());
	sort(vecm.begin(), vecm.end(), secSort);
    return 0;
}

 


什么是仿函数?

仿函数(functors)在C++标准中采用的名称是函数对象(function objects)。仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,但是函数指针不能满足STL对抽象性的要求也不能满足软件积木的要求–函数指针无法和STL其他组件搭配,产生更灵活变化。仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象。

使用仿函数必须包含:<functional>头文件。先看看STL的一个仿函数,less<_Ty>

template<class _Ty = void>
    struct less
    {    // functor for operator<
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type;
    _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool result_type;

    constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
        {    // apply operator< to operands
        return (_Left < _Right);
        }
    };

乍一看,挺麻烦的,其实只要抓住几个要点就可以自定义仿函数了:

  1. 仿函数的类必须重载operator()运算符;
  2. 重载operator()运算符时必须在函数声明后面const,即是一个常量成员函数,这是因为定义的类要跟binder2nd 一致,binder2nd 的 operator() 后面有个 const;

实例

#include <iostream>
#include <map>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <list>

class secSort {
public:
	bool operator() (string x, string y)const {
		return x.length() > y.length();
	}
};

int main()
{

	map<string, int, secSort> name_score_map;
	name_score_map["LiMin"] = 90;
	name_score_map["ZiLinMi"] = 79;
	name_score_map["BoB"] = 92;
	name_score_map.insert(make_pair("Bing", 99));
	name_score_map.insert(make_pair("Albert", 86));
	return 0;
}

上面代码中的secSort就是一个仿函数,在定义仿函数类的时候可以不表明继承了binary_function与unary_function,其实在编译的时候可以自动识别出,一个现象就是:如果重载operator()时不是常量成员函数,那么就会报错。

上述仿函数实现的是:按照key(string类型)的长度大小排序。如果要实现按照value排序,可以直接在secSort类中把重载函数的参数改为int吗?这是绝对不可以的,因为map默认是按照key值排序的。

事实上,STL中pair的排序方式决定了map的排序。

template<class _T1, class _T2>  
  inline bool  
  operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)  
  { return __x.first < __y.first  
           || (!(__y.first < __x.first) && __x.second < __y.second); } 

STL源码中pair已经重载了<号,所以不可以在定义map的时候按照value排序,但是可以参照第一段代码用vector实现按照value排序。

发布了55 篇原创文章 · 获赞 29 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/ruibin_cao/article/details/94414978