facebook folly库for_each的源码解析(上)

for_each可以说是函数式编程的一个重要的功能组件。譬如以简练著称的scala语言,本身就是一个原生的函数式语言,将一个map中的key, value遍历打印出来,我们可以写出以下代码:

 

val b = Map( “a” -> 1, “b” -> 2, “c” -> 3 )

b.foreach( x => println( x._1 + "  " + x._2.toString ) )

 

可以说是相当的清晰简练。

 

c++虽然不是函数式编程语言,但是STL的头文件中提供的for_each也可可以达到scala相同的效果,下面用c++ 11中可以快速写出类似以下的语句来遍历一个map

 

map b = { { “a”, 1 }, {“b”, 2}, {“c”, 3 } }

std::for_each( b.begin(), b.end(), [](auto v){ cout << v.first << "   " << v.second << endl; } );

 

其中利用了c++11的lamba函数,相比scala, C++上述写法略显复杂,但是也还算清晰。for_each + lambda函数让c++也具备了类似函数式编程的功能。

 

但是标准库的for_each只能对数组或者容器对象进行遍历,c++11中还引入了tuple,即元组类型,tuple是一个可以容纳不同类型(异质,heterogeneous)值的集合(这一点是tuple与其他常规STL容器的最大不同,即它可以同时存放不同类型的数据),也是泛化的std::pair(也即std::pair是元素数量限制为2个的tuple的一个特例)。

 

虽然tuple类似于stl中的各种集合对象,但是实质上它更像是一个结构体,因为tuple是没有begin和end方法函数,以及iterator迭代器的,因此标准库的for_each是不能够对tuple进行循环迭代的。如果能够像集合对象一样能够对tuple中的元素进行迭代,是不是会更美一些?

 

folly 利用c++的模板元编程技术实现了folly版本的for_each就提供了这个功能。直接用folly源文件中的例子,如下:

auto range_one = std::vector{1, 2, 3};

auto range_two = std::make_tuple(1, 2, 3);

auto func = [](auto ele, auto index) {

    cout << "Element at index " << index << " : " << ele;

    if (index == 1) {

      return folly::loop_break;

    }

    return folly::loop_continue;

  };

folly::for_each(range_one, func);

folly::for_each(range_two, func);

 

 

甚至,可以对一个tuple中的不同元素指定不同的类型,for_each一样可以胜任,如:

auto t = std::make_tuple( 1, 2.0, 3.1, 4, "aa", string("xxxx") );

folly::for_each( t, [](auto v, size_t i){ cout << v << "  " << i << endl; } );

 

超出想象,C++静态语言竟然写出了类似动态解析语言的味道了,赞!

 

这样子在使用形式上,folly::for_each将对普通集合对象的迭代和tuple的迭代统一起来了。同时, for_each使用也很简单,只需要引用#include ,不需要与folly的so库链接。一定程度上提升了C++开发的体验。

你可能感兴趣的:(c++开发)