[译]C++11 sort using function objects

如果你用C++编码, 需要对容器内的元素进行排序, 这个容器提供任意访问的迭代器, 比如std::vector, 那么简单快捷的方法是使用里的std::sort 函数.

Basic sorting std::sort 函数需要两个参数, 这两个参数分别指向你要排序的序列容器的开始(initial)和终点(final). 这个序列容易内除final指向的那个元素外 所有元素都会被排序. 下面是一个简单的排序例子:

1
2
3
4
5
6
7
#include <algorithm>
#include <vector></vector></algorithm>

const int array[] {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);</int>

std::sort(vec.begin(), vec.end());

输出: 0 5 10 15 20

More complex sorting 在某些时候, 根据数值升序排序已经足够解决问题了, 但是当我们需要按某个特定的参数进行排序, 或者降序排列时, 就需要一些其他的东西了. 对于这种需求, std::sort 需要引入第三个参数: 比较函数. 这个比较函数有两个参数, 分别是序列容器的两个元素, 返回值可以隐式地转为bool. 如果第一个参数应该排在第二个参数前面, 则返回true.

例:

1
2
3
4
5
6
7
8
9
#include <algorithm>
#include <vector></vector></algorithm>

bool DescOrderInt(int a, int b);
...
const int array[] = {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);</int>

std::sort(vec.begin(), vec.end(), DescOrderInt);

DescOrderInt的实现:

1
2
3
4
bool DescOrderInt(int a, int b)
{
return a &gt; b;
}

输出: 20 15 10 5 0

C++11 sort using function objects 网上很多例子说, 为了排列元素, 可以使用std::binary_function 定义比较函数, 但不幸的是, std::binary_function 在C++11 中已经被标为 “将被弃用的”, 在C++17中会被完全移除, 所以写新的C++代码时, 最好不要用这个.

我们可以使用C++11中引入的std::function 来定义这个函数指针. 例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <algorithm>
#include <function>
#include <vector></vector></function></algorithm>

struct StrDescOrderInt
{
bool operator()(int a, int b) const
{
return a &gt; b;
}
};
...
const int array[] = {10, 20, 5, 15, 0};
std::vector<int> vec(array, array + 5);</int>

std::function<bool(int, int)=""> sorter = StrDescOrderInt();</bool(int,>

std::sort(vec.begin(), vec.end(), sorter);

输出: 20 15 10 5 0

A real-life example: providing multiple sorting options 我们假设有一队足球运动员, 我们想让用户按他们自己的意愿去排列这些运动员. 有一个图表的UI, 上面有几个按钮, 每个按钮对应不用的排序规则.

Plaer 类的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// -- Player.h --
#include <string></string>

class Player
{
public:
Player(const char * name, int caps, int goals);

const std::string &amp; GetName() const;

int GetCaps() const;
int GetGoals() const;

private:
std::string mName;

int mCaps;
int mGoals;
};

现在我们新写一个类或结构体来列出所有的比较函数. 比较函数是一个结构体并实现操作符(), 操作符() 带有两个参数, 分别为两个指向Player的指针, 返回bool值.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Player;

struct PlayerSorting
{
// name
struct SortPlayerByNameAsc (bool operator()(Player* p1, Player* p2) const;);
struct SortPlayerByNameDes (bool operator()(Player* p1, Player* p2) const;);

// caps
struct SortPlayerByCapsAsc (bool operator()(Player* p1, Player* p2) const;);
struct SortPlayerByCapsDes (bool operator()(Player* p1, Player* p2) const;);

// goals
struct SortPlayerByGoalsAsc (bool operator()(Player* p1, Player* p2) const;);
struct SortPlayerByGoalsDes (bool operator()(Player* p1, Player* p2) const;);
}

然后, 在调用它的地方, 我们可以先把所有的std::function 存在一个std::vector 里, 使用的时候, 用索引访问vector的元素.

1
2
3
4
5
6
7
std::vector< std::function<bool(player *,="" player="" *)=""> > sorters;
sorters.push_back(PlayerSorting::SortPlayerByNameAsc());
sorters.push_back(PlayerSorting::SortPlayerByCapsAsc());
sorters.push_back(PlayerSorting::SortPlayerByGoalsAsc());
sorters.push_back(PlayerSorting::SortPlayerByNameDes());
sorters.push_back(PlayerSorting::SortPlayerByCapsDes());
sorters.push_back(PlayerSorting::SortPlayerByGoalsDes());</bool(player>

例如, 根据得分降序排列:

1
2
3
4
5
std::vector<player *=""> players;</player>

// ...init players...

std::sort(players.begin(), players.end(), sorters[5]);

输出:

1
2
3
4
5
6
7
8
9
10
11
NAME                     CAPS  GOALS
Lionel Messi 21 20
David Villa 13 16
Asamoah Gyan 22 15
Arjen Robben 11 12
Mesut Oezil 19 10
Diego Forlan 20 10
Andres Iniesta 15 9
Wesley Sneijder 24 6
Xavi 17 5
Bastian Schweinsteiger 23 4

假如需要实现一种新的排序方式, 我们只需要在PlayerSorting类中添加一个新的仿函数即可.

原文地址: http://blog.davidecoppola.com/2015/01/cpp11-sort-using-function-objects/