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

Folly make_array详解

缘起

自从C++进化到了C++ 11以后,在STL库里面增加了一个std::array的新容器。std::array可以说是c++语言原生类型的更好的一个封装类型,为什么这么说呢?因为它除了有传统数组支持随机访问、效率高、存储大小固定等特点外,还支持迭代器访问、获取容量、获得原始指针等高级功能。而且它还不会退化成指针T *给开发人员造成困惑。

例如:

1std::array a{1, 1, 2, 3 };

 

std::for_each( a.begin(), a.end(), [](int v ){ cout << v << endl; } );

 

声明了一个容量为5为int型数组,并通过for_each把里面的每个元素都打印出来。

 

但是以上1的写法略显麻烦,为什么呢?首先,我们要定义array的容量和类型,另外,初始化列表中的元素还要和前面定义的类型比较严格地进行匹配。

 

如果写成:

std::array a{ 1, 2, 3,4,5,6 };

 

就编译失败了,原因很明显,就是初始化列表中的元素格式大于声明的容器大小。每次声明的时候需要数一遍初始化列表中元素的个数还真的比较麻烦,另外,后续如果要增加或者减少初始化列表中的元素,还要修改对应的array的声明,显得有些啰嗦。

 

会偷懒的勤劳的folly工程师为我们提供了make_array模板类,来简化我们的array声明工作。譬如:

 

1auto a = make_array(1,2,3,4,5);

2auto b = make_array(string(“abc”),string(“124”))

 

其中声明的a类型就是std::array, b类型就是std::array,利用C++模板的推导技术,不需要自己再一个一个数元素地数了。

对于2,咱们甚至把也省掉了,因为编译器会推导出来类型。再看下例:

auto d = make_array( 1, 1.1, 2.1, 3, 4 );

 

编译器会自动推导出d的类型为std::array

 

无论怎么说,利用make_array,至少可以为咱们省去一些幼儿园小朋友的数数游戏,让我们在编码的时候少码一些字符,避免一些错误。

 

 

源码解析

接口定义

make_array 定义在folly/container/Array.h头文件中。

其基本的就是两个模板函数,如下:

 

template

constexpr array_detail::return_type make_array(TList&&... t);

 

 

template

constexpr auto make_array_with(MakeItem const& make) ;

 

其中make_array用初始化列表来构造一个std::array,而make_array_with则用一个可调用对象(可以是编译期或运行时)来构造一个std::array。譬如:

 

 

constexpr double make_item( int index )

{

    return index * 1.1;

}

 

auto ma = folly::make_array_with<3>( make_item );

std::for_each( ma.begin(), ma.end(), [](double v ){ cout << v << endl; } );

 

 

首先定义了一个constexpr类型的make_item的编译期函数(用来在编译过程中进行动态计算),然后make_array_with声明容量为3个,调用make_item自动构建初始化列表来初始化ma函数,最后将ma中的所有double元素打印出来。

 

 

在c++14的环境下,甚至可以用constexpr lambda函数写出如下的代码来直接初始化ma:

auto ma = folly::make_array_with<3>( [](int index) constexpr ->double{ return index * 1.1; } );

 

make_array_with在编译器用来构建元素为c++的基本类型的array还是可以的,主要在于constexpr编译器函数的限制,其他类型譬如std::array的构建,还是无能为例了。

不过,如果不想用编译期函数进行编译期的初始化列表的构建,那么在运行时,make_array_with还可以做得更多,譬如:构建过程中进行其他计算,以及构建出非基本类型作为array的元素,如:

 

auto mas = folly::make_array_with<3>( [](int v)->string{

                                 cout << v << endl;

                                 return "abcdefg"; } );

 

 

这里没有constexpr的修饰,这个lamda函数就是一个运行时函数,make_array_with的初始化列表构建就在运行时进行,所以可以打印,乃至动态构造string对象了。

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