c++ 标准库里有一个函数 sort(),可以对容器的元素进行排序。它的函数原型是(参考资料 [1]):
template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
其中第三个参数是一个比较函数,它接收两个容器中的两个元素,返回比较结果。如果没有第三个参数,默认按元素的升序排列。
例如,我们要将一个整型数组降序排列:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
static bool compare_int(int a, int b)
{
return (a > b);
}
int main(void)
{
vector<int> vec = {5, 3, 1, 4, 2};
for (auto i = vec.begin(); i != vec.end(); ++i)
cout << *i << " ";
cout << endl;
sort(vec.begin(), vec.end(), compare_int);
for (auto i = vec.begin(); i != vec.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}
这里使用了 c++11 中的新特性:使用关键字 auto 自动推断变量 i 的类型,替代了显式的“vector
为了让元素降序排列,我们需要定义一个函数 compare_int() 用于比较。由于 c++ 中函数不能嵌套定义的规定,compare_int() 只能在 main() 函数外层定义,这样会导致在 compare_int() 之后定义的函数都能看到 compare_int();可是 compare_int() 只在 sort() 的时候被使用,它应该作为一个局部变量定义在 main() 中。使用新标准的 lambda 函数,上面的程序可以改写为:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void)
{
vector<int> vec = {5, 3, 1, 4, 2};
for (auto i = vec.begin(); i != vec.end(); ++i)
cout << *i << " ";
cout << endl;
sort(vec.begin(), vec.end(),
[](int a, int b) { return (a > b); });
for (auto i = vec.begin(); i != vec.end(); ++i)
cout << *i << " ";
cout << endl;
return 0;
}
新的 c++11 标准允许定义匿名函数(即函数式编程中的 lambda 函数),例如这里传递给 sort() 函数的第三个参数:
[](int a, int b) { return (a > b); }
定义了一个 lambda 函数,它接收两个整型参数 a 和 b,返回 a 和 b 的比较结果。一般来说,c++ 中的 lambda 函数的形式为(参考资料 [2]):
[ capture ] ( params ) mutable exception attribute -> ret { body }
[ capture ] ( params ) -> ret { body }
[ capture ] ( params ) { body }
[ capture ] { body }
前面的定义省略了返回值,编译器会推测返回值的类型是 decltype(a > b),即一个 bool 值。更严格的写法应该是:
[](int a, int b) -> bool { return (a > b); }
中括号里可以指定 lambda 函数中要使用的外层函数的参数和传递方法(传值还是传引用)。例如下面的代码对一个数组的所有元素求和:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(void)
{
vector<int> vec = {5, 3, 1, 4, 2};
int sum = 0;
for_each(vec.begin(), vec.end(),
[&sum](int i) { sum += i; });
cout << "sum = " << sum << endl;
return 0;
}
这里的 for_each() 会遍历容器,并把每个元素作为参数传给第三个参数 fn:
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function fn);
代码中的第三个参数是一个 lambda 函数,中括号中指定了把外层的变量 sum 作为引用传递给 lambda 函数,这样就可以在 lambda 函数中修改 sum 的值。lambda 函数支持以下的捕获变量的语法(参考资料 [2, 3]):
- []: 不捕获任何变量
使用 auto 的新语义,我们可以在函数中定义 lambda 函数并将它赋给一个变量,在重用代码的同时又限制了函数的作用域。例如经典的“helloworld”例子:
#include <iostream>
using namespace std;
int main(void)
{
auto func = [] { cout << "Hello, world." << endl; };
func();
return 0;
}
参考资料
[1] std::sort
[2] Lambda functions
[3] C++11