关于C++0x
预计于明年底推出的新标准C++0x,虽说已接近收官阶段,却仍有若干有待接纳的新提案被提出。尤其值得关注的是,与lambda表达式以及局部函数相关的提案“ Unified Function Syntax(统一的函数语法)”,尽管不受标准委员会待见(两年间历经四次延迟表决,两次不予通过),仍然“顽强地”推出了其第7个版本N2989,提案作者锲而不舍的精神实在令人钦佩。
关于lambda表达式
受函数型编程风格的影响,一些OOP为主题思想的静态语言纷纷推出了lambda这一以短小的匿名函数为特点的语言设施,典型的如微软的VB9和C#3.0。与此相对应的是,众多动态脚本语言(python, ruby, javascript)则早就具备了相应的语言特性,Ruby的过程对象便是其中一例。这一次借C++0x新标准的东风,C++语言不甘人后同样引入了这一激动人心的新特性,为函数型编程风格在C++语言内的进一步推广打下了坚实的基础。
以下用C++0x中的lambda表达式来模拟Ruby的过程对象。
Ruby代码
class Array def inject(n) each { |value| n = yield(n, value) } n end def sum inject(0) { |n, value| n + value } end def product inject(1) { |n, value| n * value } end def find for i in 0...size value = self[i] return value if yield(value) end return nil end end [ 1, 2, 3, 4, 5 ].sum # 15 [ 1, 2, 3, 4, 5 ].product # 120 [ 1, 2, 3, 4, 5 ].find {|v| v*v > 10 } # 4
有关Ruby的过程对象以及这段Ruby代码的说明,请参考 Ruby语言中的泛回调及其在C++语言中的模拟实现一文。
C++代码
#include <array> #include <functional> //#include <numeric> #include <algorithm> #include <boost/assign.hpp> #include <iostream> using namespace std; template<typename T> struct Array : public vector<T> { template<typename _Iter> Array(_Iter _First, _Iter _Last) : vector(_First, _Last) {} T inject(T n, function<T(T,T)> f) const { for_each(begin(), end(), [&](T value){n = f(n, value);}); return n; //return accumulate(begin(), end(), n, f); } T sum() const { return inject(0, [](T n, T value){return n + value;}); } T product() const { return inject(1, [](T n, T value){return n * value;}); } const T* find(function<bool(T)> f) const { auto i = find_if(begin(), end(), f); return i == end() ? nullptr : &*i; } }; int main() { Array<int> a = boost::assign::list_of(1)(2)(3)(4)(5); //Array<int> a = {1, 2, 3, 4, 5}; cout << a.sum() << endl; cout << a.product() << endl; cout << *a.find([](int v){return v * v > 10;}) << endl; return 0; } //15 //120 //4
C++代码说明
- Ruby数组用标准库的vector组件来模拟。
- Ruby数组的初始化用boost库的assign组件来模拟。
注:Array类中若加入初始化列表构造器(C++0x新特性,VC10尚不支持),其初始化方式将可得到明显改善(第36行)。
- Ruby过程对象用lambda表达式来模拟。
- Ruby代码中的each方法用标准库的for_each算法来模拟。
- 如果不模拟具体算法,Ruby代码中的inject方法也可用标准库的accumulate算法来实现。
具体做法为:注释掉第17,18行,反注释第3,19行。
- Ruby代码中的find方法直接用标准库的find_if算法来实现(具体算法不予模拟)。
- 第28行的auto是C++0x新引入的关键字,用于自动类型推导,与C#3.0中的var相类似。
注:严格地说,是“旧瓶装新酒”,auto关键字的原意(表示自动分配的局部变量类型,由于可省略而绝少被使用)在新标准中已经被废除。
- 第29行的nullptr也是C++0x新引入的关键字,用于替代NULL表示空指针。
- 原属于Boost库的模版类function在新标准中将正式进入标准库。
function类型的变量不仅能存放函数指针和函数对象,也能存放lambda表达式。