对于像set、multiset之类有序容器,默认情况下,标准库使用关键字类型(key)的<运算符来比较两个关键词。
set<int> set ;
set.insert(7);
set.insert(3);
set.insert(10);
for (auto it = set.begin(); it != set.end(); ++it)
cout<<*it<<endl;
插入顺序是7、3、10,但是遍历map,得到的是3、7、10,这就是默认情况下int的<运算符在发挥作用,一般情况下都能满足要求。
但是要是我们不需要自定义的排序规定,想要自己定义规则,怎么办?
比如现在有两个数据,第一个是年龄,第二个是名字,年龄从小到大排序,如果年龄相同,按字符串排序方式。有些人可能想用map<int, string>, 但是map的排序规则也是针对key,就是前面那个int,不会探究后面那个string。
方法1:定义一个数据类和比较类
这个时候可以自定义一个数据类,这个类就包含两个数据成员,一个age,一个name,还有一个构造函数。然后定义一个比较类,对message进行自定义的比较规则。如果年龄相等,比较名字。如果年龄不相等,比较年龄。
class message {
public:
int age;
string name;
message(int x, string y): age(x),name(y){};
};
class messageCmp {
public:
bool operator()(const message &a, const message &b) {
if (a.age == b.age)
return a.name < b.name;
else
return a.age < b.age;
}
};
接着我们定义具备messageCmp规则的set,插入三个值。对于字符串“Jbse”和“Jane”,因为前者第二个字母是b,后者第二个字母是a,所以后者比较小。可以看到输出是按照我们预想的排序进行。
set<message, messageCmp> set ;
set.insert(message(7,"Tony"));
set.insert(message(4,"Jbse"));
set.insert(message(4,"Jane"));
for (auto it = set.begin(); it != set.end(); ++it)
cout<<it->age<<"->"<<it->name<<endl;
方法2:定义一个比较函数
这是另外的一种方式,创建了一个新的函数。
bool messageCmp(const message &a, const message &b) {
if (a.age == b.age)
return a.name < b.name;
else
return a.age < b.age;
}
int main() {
set<message, decltype(messageCmp)*> set(messageCmp) ;
set.insert(message(7,"Tony"));
set.insert(message(4,"Jbse"));
set.insert(message(4,"Jane"));
for (auto it = set.begin(); it != set.end(); ++it)
cout<<it->age<<"->"<<it->name<<endl;
在定义set的时候必须提供两个类型:关键字类型,即message,以及比较操作类型(一种函数指针类型),指向messageCmp函数。
C++11新标准引入了类型指示符decltype,它的作用是返回操作数的数据类型。decltype的结果是函数类型,所以只有在后面加上*才能表示给定函数类型的指针。用messageCmp来初始化set,表示我们在往set添加元素的时候,通过调用messageCmp函数为元素排序。