【问题标题】:Compile-time generate integer sequence with one left out编译时生成一个省略的整数序列
【发布时间】:2015-01-23 08:25:00
【问题描述】:

答案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 是序列的长度,I 是缺少的索引或其他变体.

我认为大部分问题已经在链接问题中得到解答。但是,我无法真正理解如何为第二个参数合并“不考虑这个”条件。

理想情况下,我希望坚持使用 c++11 的特性并避免使用 c++14。不过,使用 c++14 的优雅且特别易读的解决方案也可能非常有趣。

【问题讨论】:

    标签: c++ templates c++11


    【解决方案1】:

    您可以使用以下内容:

    #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

    【讨论】:

      【解决方案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 的不同,这不会在现有算法的基础上构建新算法,而是从头开始构建新算法。

      【讨论】:

        【解决方案3】:

        写下您的问题总是很棒。

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

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

        【讨论】:

          猜你喜欢
          • 2017-03-06
          • 2021-05-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-20
          • 1970-01-01
          • 1970-01-01
          • 2021-10-03
          相关资源
          最近更新 更多