How to create a sorted mapping integer index with templates

前端 未结 2 651
情话喂你
情话喂你 2021-02-10 07:34

I have the data structure:

template  struct index {};

template  struct data {};

template  struct X
{
            


        
2条回答
  •  名媛妹妹
    2021-02-10 08:22

    I'll share my approach to this problem which I think is kind of neat. I used C++11 std::conditional, and C++14 std::integer_sequence and std::make_integer_sequence, all of which you can find implementations of online.

    Let's start with the data structures you had.

    template  struct index {};
    template  struct list {};
    template  struct pair {};
    

    We'll use a metafunction concat, which concatenates N list of types. We use it to filter a list by returning list when the predicate returns true, and list<> otherwise.

    For example, to filter the even numbers from list<1, 3, 2, 4, 2>, we can perform std::conditional_t, list<>> for each I to get concat_t, list<>, list<2>, list<4>, list<2>> = list<2, 4, 2>.

    template  struct concat;
    
    template <> struct concat<> { using type = list<>; }
    
    template 
    struct concat> { using type = list; };
    
    template 
    struct concat, list> { using type = list; };
    
    template 
    struct concat, list, Tail...>
        : concat, Tail...> {};
    
    template 
    using concat_t = typename concat::type;
    

    Now we get to build_index. We perform bucket sort within the known range of [0, 32). We could have used a generic sorting algorithm, but it was more fun to cheat.

    template  struct build_index;
    
    // e.g., `build_index<
    //            1, list, pair<1, 2>, pair<2, 1>, pair<1, 6>, pair<1, 3>>`
    template 
    struct build_index...>> {
      // Filter for pairs where `N == lhs`, and replace the `lhs` with the index.
      template 
      static auto filter(std::integer_sequence)
          -> concat_t>, list<>>...>;
    
      // e.g., `list, pair<3, 6>, pair<4, 3>>`
      using filtered =
          decltype(filter(std::make_integer_sequence{}));
    
      // `get(set)` returns the `lhs` if `set` can implicitly convert to
      // `pair` for some `lhs`, and nothing otherwise.
      template  struct set : Ts... {};
      template  static list> get(pair);
      template  static list<> get(...);
    
      // We invoke `get` for `I` in `[0, 32)` to sort `filtered`.
      template 
      static auto sort(std::integer_sequence, list)
          -> concat_t(set{}))...>;
    
      // e.g., `list, index<4>, index<3>>`
      using sorted =
          decltype(sort(std::make_integer_sequence{}, filtered{}));
    
      // e.g., `list<1, 4, 3>`
      template  static index indices(list...>);
      using type = decltype(indices(sorted{}));
    };
    
    template 
    using build_index_t = typename build_index::type;
    

    With which we get:

    using index_t = build_index_t<
        1, list, pair<1, 2>, pair<2, 1>, pair<1, 6>, pair<1, 3>>>;
    static_assert(std::is_same, index_t>::value, "");
    

提交回复
热议问题