【模板进阶】std::integer_sequence

一、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 intunsigned 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,N1>,即 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;
}

运行结果如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值