杂谈C++11一个有趣的设计——std::_Build_index_tuple

Posted 彼 方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杂谈C++11一个有趣的设计——std::_Build_index_tuple相关的知识,希望对你有一定的参考价值。

1、源码准备

本文是基于gcc-4.9.0的源代码进行分析,std::_Build_index_tuple是C++11才加入标准的,所以低版本的gcc源码是没有这个的,建议选择4.9.0或更新的版本去学习,不同版本的gcc源码差异应该不小,但是原理和设计思想的一样的,下面给出源码下载地址
http://ftp.gnu.org/gnu/gcc

2、使用方法

std::_Build_index_tuple是C++11新增的一个类模板,主要是为了生成一个std::_Index_tuple<…>的结构,下面通过一个简单的例子看一下std::_Build_index_tuple的使用方法

#include <iostream>
#include <tuple>

template<size_t... _Indexes>
void print(const std::_Index_tuple<_Indexes...>&)
{
    std::initializer_list<int> indexes = {_Indexes...};
    for (auto index : indexes)
        std::cout << index << " ";
    std::cout << std::endl;
}

int main(int argc, char* argv[])
{
    print(std::_Build_index_tuple<10>::__type());
}

输出结果如下

0 1 2 3 4 5 6 7 8 9

从代码中可以看到,print是一个可变参函数,其传入参数类型是const std::_Index_tuple<_Indexes…>&,而我们在主函数调用时传入的是std::_Build_index_tuple<10>::__type(),再结合最终的输出结果,我们可以知道这里std::_Build_index_tuple<10>::__type()生成的结果是std::_Index_tuple<0, 1, 2,…, 9>。从而可以推断出std::_Build_index_tuple可以生成一个std::_Index_tuple<0, …, N - 1>的结构,其中N >= 1

3、源码解析

std::_Build_index_tuple有可能位于libstdc++-v3\\include\\std\\utility中,也有可能位于libstdc++-v3\\include\\std\\tuple中,源代码版本不同是有区别的

3.1、_Index_tuple解析

// Stores a tuple of indices.  Used by tuple and pair, and by bind() to extract the elements in a tuple
template<size_t... _Indexes>
struct _Index_tuple
{
    typedef _Index_tuple<_Indexes..., sizeof...(_Indexes)> __next;
};

先看一下_Index_tuple的实现,内容很简单,就是计算出传入参数的个数(sizeof…(_Indexes)的作用就是计算出可变参的数量),然后再其最后添加上这个数字,形成一个新的_Index_tuple。下面举例说明一下,加深大家对这个的理解

例1:_Index_tuple<0, 1, 2, 3>::__next 展开之后会变为 _Index_tuple<0, 1, 2, 3, 4>
当然,你传入_Index_tuple的参数当然可以是无规则的,示例如下
例2:_Index_tuple<3, 8, 11, 2>::__next 展开之后会变为 _Index_tuple<3, 8, 11, 2, 4>

3.2、_Build_index_tuple解析

// Builds an _Index_tuple<0, 1, 2, ..., _Num-1>.
template<size_t _Num>
struct _Build_index_tuple
{
    typedef typename _Build_index_tuple<_Num - 1>::__type::__next __type;
};

template<>
struct _Build_index_tuple<0>
{
    typedef _Index_tuple<> __type;
};

这个一看就是个递归模板,因为_Build_index_tuple有个全特化形式用于结束递归。咋一看这东西有点难理解,下面就使用数学归纳法证明我们前面所提到的那个结论,即std::_Build_index_tuple = std::_Index_tuple<0, …, N - 1>,这里要注意N >= 1

  1. _Num的值为1时,_Build_index_tuple<1>::__type = _Build_index_tuple<0>::__type::__next = _Index_tuple<>::__next = _Index_tuple<0>,成立
  2. _Num的值为2时,_Build_index_tuple<2>::__type = _Build_index_tuple<1>::__type::__next
    而从上面我们已经知道了_Build_index_tuple<1>::__type = _Index_tuple<0>
    则可将前面的等式可变为_Build_index_tuple<2>::__type = _Index_tuple<0>::next = _Index_tuple<0, 1>,成立
  3. 假设当_Num的值为N(N >= 2)时,成立,即std::_Build_index_tuple = std::_Index_tuple<0, …, N - 1>
    _Num的值为N+1(N >= 2)时,_Build_index_tuple<N + 1>::__type = _Build_index_tuple::__type::__next
    这里将前面假设的_Build_index_tuple::__type = _Index_tuple<0, …, N - 1>代入,
    可得_Build_index_tuple<N + 1>::__type = _Index_tuple<0, …, N - 1>::next = _Index_tuple<0, …, (N + 1) - 1>,成立

从上面的证明中我们可以看到_Build_index_tuple::__type的类型确实是_Index_tuple<0, 1, 2, …, N-1>,它其实就是利用了模板递归展开来实现的。

4、总结

本文介绍了C++11新增的一个类模板std::_Build_index_tuple的使用方法和实现原理,当然这玩意平时开发应该也用不上,他主要是给标准库使用的,从官方给的注释中可以看到它是给std::tuplestd::pairstd::bind提供服务的,以后我也会写这几个相关的文章,到时就可以看到std::_Build_index_tuple的具体使用场景了。

最后,如果大家觉得本文写得好的话麻烦点赞收藏关注一下谢谢,也可以关注该专栏,以后会有更多优质文章输出的。

以上是关于杂谈C++11一个有趣的设计——std::_Build_index_tuple的主要内容,如果未能解决你的问题,请参考以下文章

使用 std::thread 函数 C++11 将指针作为参数传递

C++11的std::function源码解析

C++11的std::mem_fn源码解析

权限设计的杂谈

C++/C++11中std string用法汇总

将 std::__cxx11::string 转换为 std::string