张银峰的编程课堂

C++:一个以继承方式展开模板参数包的步步解析

我们来分析一下主函数中T的最终类型是什么。

// T1
template<int...>
struct IndexSeq {};

// T2
template<int N, int... Indices>
struct MakeIndices : MakeIndices<N - 1, N - 1, Indices...> {};

// T3
template<int... Indices>
struct MakeIndices<0, Indices...>
{
    typedef IndexSeq<Indices...> type;
};

int main()
{
    using T = MakeIndices<3>::type;
}

MakeIndices<3>

非类型参数构成类型的一部分,因此 MakeIndices<3> 也是一个独一无二的类型。

类型 MakeIndices<3> 匹配模板T2,不过参数包里没有模板参数,由此展开生成如下代码:

struct MakeIndices<3> : public MakeIndices<2, 2> // 参数包参数个数为0,展开后就是没有
{
};

MakeIndices<2, 2>

类型 MakeIndices<2, 2> 匹配模板T2,参数包有1个参数,值为2,由此展开生成如下代码:

struct MakeIndices<2, 2> : public MakeIndices<1, 1, 2> // 参数包有1个值为2(后面的那个2)的参数
{
};

MakeIndices<1, 1, 2>

类型 MakeIndices<1, 1, 2> 匹配模板T2,参数包有2个参数,值为1,2,由此展开生成如下代码:

struct MakeIndices<1, 1, 2> : public MakeIndices<0, 0, 1, 2>
{
};

MakeIndices<0, 0, 1, 2>

类型 MakeIndices<0, 0, 1, 2> 匹配特化模板T3,参数包有3个参数,值为0,1,2,由此展开生成如下代码:

struct MakeIndices<0, 0, 1, 2>
{
    typedef IndexSeq<0, 1, 2> type;
};

MakeIndices<3>::type

由此 MakeIndices<3>::type 的类型为:struct IndexSeq<0, 1, 2>