编译时生成整数序列,其中一个省略

时间:2014-11-25 11:03:02

标签: c++ templates c++11

答案herehere几乎是我所需要的。但是,我希望能够生成如下序列:

gen_seq<5, 2> // {0, 1, 3, 4}
gen_seq<3, 0> // {1, 2}
// optional behavior that would be useful for me:
gen_seq<4, 4> // {0, 1, 2, 3}

在示例中,我使用gen_seq生成从0到N-1而没有I的序列。这不是强制性的,我也可以使用gen_seq,其中N是序列的长度,我是缺失的索引或其他变体

我认为大部分问题已在相关问题中得到解答。但是,我无法真正理解如何整合&#34;留下这个&#34;条件为第二个参数。

理想情况下,我希望坚持使用c ++ 11功能并避免使用c ++ 14。然而,使用c ++ 14的优雅且特别易读的元素也可能非常有趣。

3 个答案:

答案 0 :(得分:8)

您可以使用以下内容:

#if 1 // Not in C++11 // make_index_sequence
#include <cstdint>

template <std::size_t...> struct index_sequence {};

template <std::size_t N, std::size_t... Is>
struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};

template <std::size_t... Is>
struct make_index_sequence<0u, Is...> : index_sequence<Is...> { using type = index_sequence<Is...>; };

#endif // make_index_sequence

namespace detail
{
    template <typename Seq1, std::size_t Offset, typename Seq2> struct concat_seq;

    template <std::size_t ... Is1, std::size_t Offset, std::size_t ... Is2>
    struct concat_seq<index_sequence<Is1...>, Offset, index_sequence<Is2...>>
    {
        using type = index_sequence<Is1..., (Offset + Is2)...>;
    };
}

template <std::size_t N, std::size_t E>
using gen_seq = typename detail::concat_seq<typename make_index_sequence<E>::type, E + 1, typename make_index_sequence<(N > E) ? (N - E - 1) : 0>::type>::type;

static_assert(std::is_same<index_sequence<0, 1, 3, 4>, gen_seq<5, 2>>::value, "");
static_assert(std::is_same<index_sequence<1, 2>, gen_seq<3, 0>>::value, "");
static_assert(std::is_same<index_sequence<0, 1, 2, 3>, gen_seq<4, 4>>::value, "");

Live example

答案 1 :(得分:2)

生成整数序列的简单线性方法可以轻松地适应于排除特定项目,方法是添加一个专门化,涵盖项目是被排除的项目的情况:

#include <iostream>

// general case, ignores X

template <int N, int X, int... vals>
struct gen_seq : gen_seq<N - 1, X, N - 1, vals...> { };

template <int X, int... vals>
struct gen_seq<0, X, vals...> { static constexpr int values[] = { vals... }; };

// specialisations when vals has had X prepended: remove X

template <int N, int X, int... vals>
struct gen_seq<N, X, X, vals...> : gen_seq<N, X, vals...> { };

template <int... vals>
struct gen_seq<0, 0, 0, vals...> : gen_seq<0, 0, vals...> { };

template <int X, int... vals>
constexpr int gen_seq<0, X, vals...>::values[];

int main() {
  for (auto i : gen_seq<5, 2>::values) std::cout << i << std::endl; // 0 1 3 4
  for (auto i : gen_seq<3, 0>::values) std::cout << i << std::endl; // 1 2
  for (auto i : gen_seq<4, 4>::values) std::cout << i << std::endl; // 0 1 2 3
}

它可能没有其他更高级的方法那么高效,但它是最具可读性的。与您自己的答案和Jarod42不同,这不会在预先存在的算法之上构建新算法,而是从头开始构建新算法。

答案 2 :(得分:1)

总是很好地写下你的问题。

我只是发现我可以使用分而治之的方法并且不会产生从0到N / 2和N / 2 + 1到n,但是在第一步中只生成从0到I - 1并且从I + 1到N.

这个,我可以结合线性或对数深度生成方法。 现在我觉得愚蠢,但至少我不再被困了。

相关问题