我一直在阅读有关int序列的资料,但我对下面的程序是如何工作的有困难。有谁能给我详细解释一下这个程序吗?为了我的考试准备,必须要掌握这个窍门。谅谅
template<int ...>
class containers
{
};
template<int C, int N, int... Is>
class rever_seq : rever_seq <C - 1, N, N - C, Is...>
{
};
template<int N, int... Is>
class rever_seq<0, N, Is...>
{
public:
using type = containers<N, Is...>;
};
template<int N>
using RSSeq = typename rever_seq<N, N>::type;
template<int... Is>
void Revseequence(containers<Is...>&& s)
{
for (auto i : { Is... }) std::cout << i << " ";
std::cout << std::endl;
}
int main()
{
Revseequence(RSSeq<5>());
}
假设你已经知道背后的理论 variadic template
我建议最好的方法是 "手动展开 "模板定义。
大多数情况下,变量模板都会采用递归的方法。
让我们试着做这个练习。
核心部分是 RS<5>()
. 这只是一个实例 rev_seq<5, 5>::type
. 好吧,让我们深入到 rev_seq
.
其声明。
template<int C, int N, int... Is>
struct rev_seq // ...
所以该实例将被 "映射"。
template<5, 5, $>
struct rev_seq // ...
其中 $
只是一个占位符,用来表示一个空的变量列表。
rev_seq
递归继承。
template<5, 5, $>
struct rev_seq : rev_seq <4, 5, 0, $> {}
当然 rev_seq <4, 5, 0, $>
(即。rev_seq<4, 5, {0}>
)继承,以此类推。
<5, 5, $> ->
<4, 5, {0}> ->
<3, 5, {1, 0}> ->
<2, 5, {2, 1, 0}> ->
<1, 5, {3, 2, 1, 0}> ->
<0, 5, {4, 3, 2, 1, 0}>
当第一个模板参数是 0
我们停止。因为在这种情况下,我们有一个 部分模板专用化.在这里,你可以看到类比与。"基本情况" 中的递归策略。
因此,我们最终得到这种继承。
struct rev_seq<0, N, Is...>
{
using type = ints<N, Is...>;
};
在你的案例中
struct rev_seq<0, 5, {4, 3, 2, 1, 0}>
{
using type = ints<5, {4, 3, 2, 1, 0}>;
};
请注意... ints
只是一个变量列表。也就是。ints<5, {4, 3, 2, 1, 0}>
实际上是 ints<{5, 4, 3, 2, 1, 0}>
.
所以,最后,你只是用这个特定的实例调用 "打印函数"。ints
:
template<{5, 4, 3, 2, 1, 0}>
void fU(ints<{5, 4, 3, 2, 1, 0}>&& s)
{
for (auto i : { 5, 4, 3, 2, 1, 0 }) std::cout << i << " ";
std::cout << std::endl;
}
请注意,这不是一个有效信息 C++ 语法,但更多的只是一个 "图形表示",旨在显示递归过程。
RS<2>()
实例化 rev_seq<2, 2>::type
rev_seq<2, 2>::type
是 rev_seq 的主模板 (不是专用模板)。
template<int C, int N, int... Is>
struct rev_seq : rev_seq<C - 1, N, N - C, Is...>{}
这是一个递归声明,所以它从自己的一个版本派生出来,就像这样。
rev_seq<2, 2, (empty int... Is pack)>
派生自
rev_seq<2-1, 2, 2 - 2>
也就是 rev_seq<1, 2, 0>
那 0
尾部的部分 int... Is
础班
这一点再次出现
rev_seq<1, 2, 0>
源于
rev_seq<1-1, 2, 2-1, 0>
也就是 rev_seq<0, 2, (1, 0)>
看看最后一个参数参数是如何被附加到包中的?
rev_seq<0, 2, (1, 0)>
匹配以下模板 专业化 对于 rev_seq
:
template<int N, int... Is>
struct rev_seq<0, N, Is...>
{
using type = ints<N, Is...>;
};
注意到这一点 struct
无源之水
在这一点上。type
类中的类型变成
ints<2, 1, 0>
请看专业化是如何使我们附加了 N
到序列的前面?
最后,我们将构建的 ints
到一个函数。
template<int... Is>
void fU(ints<Is...>&& s)
{
for (auto i : { Is... }) std::cout << i << " ";
std::cout << std::endl;
}
循环对整数进行迭代。
for (auto i : { Is... })
喏 { Is...}
是一个包的扩展,为我们创建了一个初始化器列表来进行迭代。值得注意的是,这是少数几个可以直接创建和使用初始化列表的地方之一,几乎所有其他的情况都是为了匹配某个类的std::initializer_list构造函数重载(例如。std::vector
)