C++标准库中integer_sequence,以及说明
make_integer_sequence
如何实现的
想要看懂,需要有基础的模板知识,最好能够手动实现。
以下代码都是自己手动编写,在use
命名空间中,命名和标准库也会有区别,但不大。
同时,以下代码拼接起来可以执行。
1 integer_seq和index_seq
原始定义很简单。
首先,模板中定义了一个类型参数,表示该模板存储数值的类型。其次,定义了一个非类型参数包,存储特定类型的数值。
template <typename _T, _T... _Ns>
struct integer_seq {
typedef _T value_type;
static constexpr size_t size() { return sizeof...(_Ns); }
};
template <size_t... _N>
using index_seq = integer_seq<size_t, _N...>;
2 make_integer_seq和make_index_seq
make_integer_seq
和make_index_seq
都是将N展开为一系列索引值
解释看代码
// 这个用作将 N 展开为 0 ... N 的一个辅助类的声明,定义在下一个标题
template <typename _Seq, typename _T, size_t _N>
struct __make_integer_seq;
template <typename _T, _T _N>
using make_integer_seq = typename __make_integer_seq<integer_seq<_T>, _T, _N>::type;
template <size_t _N>
using make_index_seq = make_integer_seq<size_t, _N>;
3 __make_integer_seq的实现
template <typename _T, size_t... _Ns>
struct __make_integer_seq<use::integer_seq<_T, _Ns...>, _T, 0> {
typedef use::integer_seq<_T, _Ns...> type;
};
template <typename _T, size_t _N, size_t... _Ns>
struct __make_integer_seq<use::integer_seq<_T, _Ns...>, _T, _N> {
typedef typename __make_integer_seq<use::integer_seq<_T, _N - 1, _Ns...>, _T, _N - 1>::type
type;
};
从这里可以看到,__make_integer_seq
中的 integer_seq
类型参数是_T
。但本质上,索引值的类型依然是 size_t
。
原因是:在类模板中,无法对未知类型参数所定义的非类型参数特例化为字面量。
如下:
将__make_integer_seq
的模板参数 size_t
替换为 _T
,之后,对类模板展开的边界条件进行限制,限制值为 _T{}
。
这是错误的,不可以将_N
特例化为 _T{}
。但是,这种形式的写法在函数模板和变量模板中好像是允许的。
template <typename _Seq, typename _T, _T _N>
struct __make_integer_seq;
template <typename _T, size_t... _Ns>
struct __make_integer_seq<use::integer_seq<_T, _Ns...>, _T, _T{}> {
typedef use::integer_seq<_T, _Ns...> type;
};