一、std::integer_sequence的介绍
1.1 s t d : : i n t e g e r _ s e q u e n c e std::integer\_sequence std::integer_sequence
s t d : : i n t e g e r _ s e q u e n c e std::integer\_sequence std::integer_sequence是 C + + 14 C++14 C++14引入的的类模板,主要用于生成一个整型数字序列的,如 [ 0 , 1 , 2 , 3 , 4 , 5 ] [0,1,2,3,4,5] [0,1,2,3,4,5]这样的序列。
具体而言,这个类模板的代码大概如下:
//integer_sequence
template<class T,T... Ints>
struct interger_sequence {
using value_type = T;
static constexpr size_t size() noexcept {
return sizeof...(Ints);
}
};
这里的 T T T一般使用的是 i n t 、 u n s i g n e d i n t int、unsigned \ int int、unsigned int等类型。
1.2 s t d : : m a k e _ i n t e g e r _ s e q u e n c e std::make\_integer\_sequence std::make_integer_sequence
s t d : : m a k e _ i n t e g e r _ s e q u e n c e std::make\_integer\_sequence std::make_integer_sequence是 s t d : : i n t e g e r _ s e q u e n c e std::integer\_sequence std::integer_sequence的别名模板,大概是如下的伪代码:
template<typename T,T N>
using make_integer_sequence = std::integer_sequence<T,0,1,2,...,N-1>;
以下是它的简单使用:
//make_integer_sequence
void Test1() {
std::make_integer_sequence<int, 5> tmpobj;
std::cout << "type = " << typeid(decltype(tmpobj)).name() << std::endl;
}
可以发现,类型如下:
1.3 s t d : : m a k e _ i n d e x _ s e q u e n c e std::make\_index\_sequence std::make_index_sequence
s t d : : m a k e _ i n d e x _ s e q u e n c e std::make\_index\_sequence std::make_index_sequence是对 s t d : : m a k e _ i n t e g e r _ s e q u e n c e std::make\_integer\_sequence std::make_integer_sequence的简化,指定第一个 T = s t d : : s i z e _ t T = std::size\_t T=std::size_t类型,只需要传入一个整数即可:
形式上大概如一下的伪代码:
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t,0,1,2,...,N-1>
一个简单的使用如下:
void Test2() {
std::make_index_sequence<10>tmpobj;
std::cout << "type = " << typeid(decltype(tmpobj)).name() << std::endl;
}
运行结果如下:
二、正向排列数字生成一个类型 I n t e g e r _ S e q u e n c e Integer\_Sequence Integer_Sequence
我们实现一个类 I n t e g e r _ S e q u e n c e Integer\_Sequence Integer_Sequence,来完成 s t d : : m a k e _ i n t e g e r _ s e q u e n c e std::make\_integer\_sequence std::make_integer_sequence的功能
以下代码实现相应的类模板:
//向后插入元素
//泛化版本只声明不定义
template<typename INTSEQ,unsigned int NewElem>
struct IntSeq_PushBack;
//特化版本
template<typename T,unsigned int... Elems,unsigned int NewElem>
struct IntSeq_PushBack<std::integer_sequence<T, Elems...>, NewElem> {
using type = std::integer_sequence<T, Elems..., NewElem>;
};
//正向排列数字生成一个类型Integer_Sequence
//泛化版本
template<typename T,unsigned int N>
struct Integer_Sequence { //实现std::make_integer_sequence功能
using type = typename IntSeq_PushBack<typename Integer_Sequence<T, N - 1>::type, N - 1>::type;
};
//特化版本,用于结束递归
template<typename T>
struct Integer_Sequence<T,1> { //递归到1即可
using type = std::integer_sequence<T, 0>;
};
其中, I n t S e q _ P u s h B a c k IntSeq\_PushBack IntSeq_PushBack类用于辅助插入的,每次放入一个数,递归调用 I n t S e q _ P u s h B a c k IntSeq\_PushBack IntSeq_PushBack,直到递归到 N = 1 N = 1 N=1的时候,调用 I n t e g e r _ S e q u e n c e < T , 1 > Integer\_Sequence<T,1> Integer_Sequence<T,1>的特化版本结束。
注意此时最后插入的元素是 0 0 0,因此是 s t d : : i n t e g e r _ s e q u e n c e < T , 0 > std::integer\_sequence<T,0> std::integer_sequence<T,0>
也可以为其实现一个别名模板,代码十分简单:
//别名模板
template<typename T,unsigned int N>
using Integer_Sequence_T = typename Integer_Sequence<T, N>::type;
以下调用我们自定义的 I n t e g e r S e q u e n c e Integer_Sequence IntegerSequence
void Test3() {
Integer_Sequence_T<int, 4>tmpobj;
std::cout << "type = " << typeid(decltype(tmpobj)).name() << std::endl;
Integer_Sequence<int, 4>::type tmpobj2;
std::cout << "type = " << typeid(decltype(tmpobj2)).name() << std::endl;
}
运行结果如下:
可以发现,成功实现了正向插入排列元素,即
s
t
d
:
:
m
a
k
e
_
i
n
t
e
g
e
r
_
s
e
q
u
e
n
c
e
std::make\_integer\_sequence
std::make_integer_sequence
三、反向排列数字生成一个类型 I n t e g e r _ S e q u e n c e _ R e v e r s e Integer\_Sequence\_Reverse Integer_Sequence_Reverse
同样,我们需要一个向前插入元素的辅助模板,这里同样只实现特化版本,因为泛化版本用不到:
//向前插入元素
template<typename INTSEQ,unsigned int NewElem>
struct IntSeq_PushFront;
//特化版本
template<typename T,unsigned int...Elems,unsigned int NewElem>
struct IntSeq_PushFront<std::integer_sequence<T,Elems...>,NewElem> {
using type = std::integer_sequence<T, NewElem, Elems...>;
};
//逆向排列数字生成一个类型Integer_Sequence_Reverse
//泛化版本
template<typename T, unsigned int N, unsigned int Count = 1>
struct Integer_Sequence_Reverse {
using type = typename IntSeq_PushFront<typename Integer_Sequence_Reverse<T, N - 1>::type, N - Count>::type;
};
//特化版本
template<typename T,unsigned int N>
struct Integer_Sequence_Reverse<T, N, N> { //当N = Count = 1时调用
using type = std::integer_sequence<T, N - 1>;
};
同样是递归插入,直到 N = C o u n t = 1 N = Count = 1 N=Count=1的时候调用特化版本,构造 s t d : : i n t e g e r _ s e q u e n c e < T , N − 1 > std::integer\_sequence<T,N-1> std::integer_sequence<T,N−1>,即 s t d : : i n t e g e r _ s e q u e n c e < T , 0 > std::integer\_sequence<T,0> std::integer_sequence<T,0>
同样有别名模板:
//别名模板
template<typename T,unsigned int N>
using Integer_Sequence_Reverse_T = typename Integer_Sequence_Reverse<T, N>::type;
调用测试函数:
void Test4() {
Integer_Sequence_Reverse<int, 5>::type tmpobj;
Integer_Sequence_Reverse_T<int, 5> tmpobj2;
std::cout << "type = " << typeid(decltype(tmpobj)).name() << std::endl;
std::cout << "type = " << typeid(decltype(tmpobj2)).name() << std::endl;
}
运行结果如下,实现了逆向插入序列生成 s t d : : i n t e g e r _ s e q u e n c e std::integer\_sequence std::integer_sequence的功能:
四、将一个数字重复多次生成一个类型 R e p e a t _ I n t e g e r Repeat\_Integer Repeat_Integer
最后,我们实现一个可以生成一个数多次的 i n t e g e r _ s e q u e n c e integer\_sequence integer_sequence
这里我们可以按照之前那样使用向前插入或者向后插入两种方式,也可以使用另一种方式:递归继承构造。
这里采用第二种方式,具体代码如下:
//将一个数字重新多次生成一个类型Repeat_Integer
// 泛化版本
template<std::size_t Num, std::size_t RepeatTime, typename INTSEQ = std::integer_sequence<std::size_t>>
class Repeat_Integer;
// 特化版本1,用于递归生成包含重复数字的整数序列
template<std::size_t Num, std::size_t RepeatTime, std::size_t... index>
class Repeat_Integer<Num, RepeatTime, std::integer_sequence<std::size_t, index...>>
: public Repeat_Integer<Num, RepeatTime - 1, std::integer_sequence<std::size_t, index..., Num>> {};
// 特化版本2,用于结束递归,此时生成了包含指定重复次数数字的整数序列
template<std::size_t Num, std::size_t... index>
class Repeat_Integer<Num, 0, std::integer_sequence<std::size_t, index...>> {
public:
using type = std::integer_sequence<std::size_t, index...>;
};
首先泛化版本没用,只声明不定义即可。
然后实现两个特化版本,其中一个作为递归的开始,另一个作为递归的结束。
可以发现,每次继承的基类的个数减一:
直到最后,个数为
0
0
0的时候,调用用于结束的特化版本,开始回溯:
实例化的过程如下:
也就是祖宗是个 i n d e x index index为空的类,然后依次返回递归构造。
它的别名模板也可以实现一下:
// 别名模板,方便使用生成的类型
template<std::size_t Num, std::size_t RepeatTime>
using Repeat_Integer_T = typename Repeat_Integer<Num, RepeatTime>::type;
最后,测试函数如下,其中我们可以指定初始生成的 s t d : : i n t e g e r _ s e q u e n c e std::integer\_sequence std::integer_sequence
void Test5() {
Repeat_Integer<1, 5>::type tmpobj;
std::cout << "type = " << typeid(decltype(tmpobj)).name() << std::endl;
Repeat_Integer_T<0, 10> tmpobj2;
std::cout << "type = " << typeid(decltype(tmpobj2)).name() << std::endl;
Repeat_Integer<5, 2, std::integer_sequence<std::size_t, 1, 2, 3>>::type tmpobj3;
std::cout << "type = " << typeid(decltype(tmpobj3)).name() << std::endl;
}
运行结果如下: