【问题标题】:C++ typelist make sublistC++ typelist 制作子列表
【发布时间】:2019-06-05 08:39:48
【问题描述】:

假设我有一个类型

template<typename ...Ts>
struct typelist {};

我需要从此列表中获取子列表:

template<int startInclusive, int stopExclusive, typename ...Ts>
struct sublist {
    using type = ?; //
};

例如

sublist<1, 3, int, float, double, char>::type == typelist<float, double>

start = 0 我有一个有效的尾部实现时:

template<typename ...Ts>
struct typelist {};

template<int N, typename T, typename ...Ts>
struct tail {
    using type = typename tail<N - 1, Ts...>::type;
};

template<typename T, typename ...Ts>
struct tail<0, T, Ts...> {
    using type = typelist<T, Ts...>;
};

using T = tail<1, int, double>::type;

#include <typeinfo>
#include <cstdio>

int main() {
   ::printf("%s\n", typeid(T).name());
}

但是,我无法为 start &gt; 0 找到任何工作

【问题讨论】:

    标签: c++ variadic-templates typelist


    【解决方案1】:

    像往常一样,std::index_sequence 在这里提供帮助:

    template <std::size_t Offset, typename Seq, typename Tuple> struct sublist_impl;
    
    template <std::size_t Offset, std::size_t ... Is, typename Tuple>
    struct sublist_impl<Offset, std::index_sequence<Is...>, Tuple>
    {
        using type = std::tuple<std::tuple_element_t<Offset + Is, Tuple>...>;
    };
    
    template<std::size_t startInclusive, std::size_t stopExclusive, typename ...Ts>
    using sublist = typename sublist_impl<startInclusive,
                                     std::make_index_sequence<stopExclusive - startInclusive>,
                                     std::tuple<Ts...>>::type;
    

    Demo

    【讨论】:

      【解决方案2】:

      这可能有点矫枉过正,但它确实有效:

      template<typename... Ts>
      struct typelist {};
      
      template<class Typelist, typename T>
      struct prepend;
      
      template<typename... Ts, typename T>
      struct prepend<typelist<Ts...>, T> {
          using type = typelist<T, Ts...>;
      };
      
      template<int start, int stop, int i, typename... Ts>
      struct sublist_impl {
          using type = typelist<>;
      };
      
      template<int start, int stop, int i, typename T, typename... Ts>
      struct sublist_impl<start, stop, i, T, Ts...>
      {
      private:
          static constexpr auto get_sublist_type() {
              if constexpr (i < start)
                  return typename sublist_impl<start, stop, i + 1, Ts...>::type{};
              else if constexpr (i < stop)        
                  return typename prepend<typename sublist_impl<
                      start, stop, i + 1, Ts...>::type, T>::type{};
              else
                  return typelist<>{};
          }
      
      public:
          using type = decltype(get_sublist_type());
      };
      
      template<int start, int stop, typename... Ts>
      struct sublist {
          using type = typename sublist_impl<start, stop, 0, Ts...>::type;
      };
      
      template<int start, int stop, typename... Ts>
      using sublist_t = typename sublist<start, stop, Ts...>::type;
      
      static_assert(std::is_same_v<
          sublist_t<1, 3, int, float, double, char>, typelist<float, double>>);
      
      static_assert(std::is_same_v<
          sublist_t<0, 0, int, float, double, char>, typelist<>>);
      
      static_assert(std::is_same_v<
          sublist_t<4, 4, int, float, double, char>, typelist<>>);
      
      static_assert(std::is_same_v<
          sublist_t<0, 3, int, float, double, char>, typelist<int, float, double>>);
      
      static_assert(std::is_same_v<
          sublist_t<0, 4, int, float, double, char>, typelist<int, float, double, char>>);
      

      【讨论】:

      • 我认为如果你有 C++17 并不过分。感谢constexpr-if,它非常易读
      【解决方案3】:

      只是为了好玩,std::tuple_cat() 方式

      #include <tuple>
      #include <type_traits>
      
      template<typename ...Ts>
      struct typelist
       { };
      
      template <std::size_t sI, std::size_t sE, std::size_t I, typename T>
      constexpr std::enable_if_t<(I >= sI) && (I < sE),
                                 std::tuple<typelist<T>>> getTpl ();
      
      template <std::size_t sI, std::size_t sE, std::size_t I, typename T>
      constexpr std::enable_if_t<(I < sI) || (I >= sE),
                                 std::tuple<>> getTpl ();
      
      template <typename ... Ts>
      constexpr typelist<Ts...> getList (std::tuple<typelist<Ts>...>);
      
      template <std::size_t sI, std::size_t sE, typename ... Ts,
                std::size_t ... Is>
      constexpr auto getTplList (typelist<Ts...>, std::index_sequence<Is...>)
         -> decltype( getList(std::tuple_cat(getTpl<sI, sE, Is, Ts>()...)) );
      
      template <std::size_t startI, std::size_t stopE, typename ... Ts>
      struct sublist
       {
         using type = decltype(getTplList<startI, stopE>
                               (typelist<Ts...>{},
                                std::index_sequence_for<Ts...>{}));
       };
      
      int main ()
       {
         using type1 = typename sublist<1u, 3u, int, float, double, char>::type;
         using type2 = typelist<float, double>;
      
         static_assert( std::is_same<type1, type2>::value, "!" );
       }
      

      【讨论】:

        猜你喜欢
        • 2011-10-08
        • 1970-01-01
        • 1970-01-01
        • 2018-04-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多