编译时的int序列

问题描述 投票:6回答:2

我一直在阅读有关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>());
}
c++
2个回答
2
投票

假设你已经知道背后的理论 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++ 语法,但更多的只是一个 "图形表示",旨在显示递归过程。


7
投票

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)

© www.soinside.com 2019 - 2024. All rights reserved.