首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >最优雅的拆分C++ TypeList的方法

最优雅的拆分C++ TypeList的方法
EN

Stack Overflow用户
提问于 2017-10-20 15:12:38
回答 2查看 1.6K关注 0票数 8

在“现代”C++中,我有一个类型列表:

代码语言:javascript
复制
template <typename... T> struct TypeList {};

我希望根据谓词拆分类型列表,例如std::is_floating_point。更准确地说,我完整的工作示例如下:

代码语言:javascript
复制
#include <iostream>
#include <type_traits>

template <typename... T> struct TypeList {};

// SplitTypeList<> implementation defined at the end of this post...

template <typename T>
void printType()
{
  std::cout << "\n" << __PRETTY_FUNCTION__;
}

int main()
{
  struct A
  {
  };

  using typeList = TypeList<int, double, float, A, int>;

  using splited_typeList = SplitTypeList<std::is_floating_point, typeList>;

  using float_typeList = splited_typeList::predicate_is_true_typeList_type;
  using other_typeList = splited_typeList::predicate_is_false_typeList_type;

  printType<float_typeList>();
  printType<other_typeList>();
}

指纹:

代码语言:javascript
复制
g++ -std=c++17 typeList.cpp -o typeList; ./typeList

void printType() [with T = TypeList<double, float>]
void printType() [with T = TypeList<int, main()::A, int>]

我的问题:您有一个可能的更短/更优雅的解决方案,只使用C++ (C++17没有问题)和STL吗?(我不想使用像Boost这样的辅助库Hana.)。

(My动机:我不想错过一两行/超级优雅的解决方案,因为我将在其他地方广泛使用此功能)

我目前的实现是:

代码语言:javascript
复制
namespace Details
{
  template <template <typename> class PREDICATE,
            typename... TYPELIST_PREDICATE_IS_TRUE,
            typename... TYPELIST_PREDICATE_IS_FALSE>
  constexpr auto splitTypeList(TypeList<TYPELIST_PREDICATE_IS_TRUE...>,
                               TypeList<TYPELIST_PREDICATE_IS_FALSE...>,
                               TypeList<>)
  {
    return std::make_pair(TypeList<TYPELIST_PREDICATE_IS_TRUE...>(),
                          TypeList<TYPELIST_PREDICATE_IS_FALSE...>());
  }

  template <template <typename> class PREDICATE,
            typename... TYPELIST_PREDICATE_IS_TRUE,
            typename... TYPELIST_PREDICATE_IS_FALSE,
            typename T,
            typename... TAIL>
  constexpr auto splitTypeList(TypeList<TYPELIST_PREDICATE_IS_TRUE...>,
                               TypeList<TYPELIST_PREDICATE_IS_FALSE...>,
                               TypeList<T, TAIL...>)
  {
    if constexpr (PREDICATE<T>::value)
    {
      return splitTypeList<PREDICATE>(
          TypeList<TYPELIST_PREDICATE_IS_TRUE..., T>(),
          TypeList<TYPELIST_PREDICATE_IS_FALSE...>(),
          TypeList<TAIL...>());
    }
    else
    {
      return splitTypeList<PREDICATE>(
          TypeList<TYPELIST_PREDICATE_IS_TRUE...>(),
          TypeList<TYPELIST_PREDICATE_IS_FALSE..., T>(),
          TypeList<TAIL...>());
    }
  }

  template <template <typename> class PREDICATE, typename... T>
  constexpr auto splitTypeList(TypeList<T...>)
  {
    return splitTypeList<PREDICATE>(
        TypeList<>(), TypeList<>(), TypeList<T...>());
  }
}

template <template <typename> class PREDICATE, typename TYPELIST>
struct SplitTypeList;

template <template <typename> class PREDICATE, typename... TAIL>
struct SplitTypeList<PREDICATE, TypeList<TAIL...>>
{
  using pair_type = decltype(
      Details::splitTypeList<PREDICATE>(std::declval<TypeList<TAIL...>>()));
  using predicate_is_true_typeList_type = typename pair_type::first_type;
  using predicate_is_false_typeList_type = typename pair_type::second_type;
};

出于好奇,TypeList的历史指针( Alexandrescu,2002年2月1日):http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-20 16:04:55

像这样的东西可能更简单一些/更短

代码语言:javascript
复制
template< bool, template<typename> class, class... Vs >
auto FilterImpl( TypeList<>, TypeList<Vs...> v ) { return v; }

template< bool Include, template<typename> class P, class T, class... Ts, class... Vs >
auto FilterImpl( TypeList<T,Ts...>, TypeList<Vs...> ) { return FilterImpl<Include,P>(
  TypeList<Ts...>{} ,
  std::conditional_t< Include == P<T>::value, TypeList<T,Vs...>, TypeList<Vs...> >{}
  ); }

template <template <typename> class PREDICATE, typename TYPELIST>
struct SplitTypeList
{
  using predicate_is_true_typeList_type = decltype(FilterImpl<true,PREDICATE>( TYPELIST{}, TypeList<>{} ));
  using predicate_is_false_typeList_type = decltype(FilterImpl<false,PREDICATE>( TYPELIST{}, TypeList<>{} ));
};
票数 6
EN

Stack Overflow用户

发布于 2017-10-20 16:01:35

我不认为下面的方式更好或者更优雅。

不一样,这是我的方式。

只使用各种模板类的专门化;不使用函数。

也应该与C++11一起工作。

希望这个例子有帮助。

代码语言:javascript
复制
#include <tuple>
#include <type_traits>

template <template <typename> class Pred, typename>
struct PredValFirst : public std::false_type
 { };

template <template <typename> class Pred,
          template <typename...> class C,
          typename T0, typename ... Ts>
struct PredValFirst<Pred, C<T0, Ts...>> : public Pred<T0>
 { };


template <template <typename> class Pred, typename List,
          typename = std::tuple<>, typename = std::tuple<>,
          bool = PredValFirst<Pred, List>::value>
struct SplitTypeList;

template <template <typename> class Pred, template <typename...> class C,
          typename T0, typename ... Ts, typename ... Tt, typename Lf>
struct SplitTypeList<Pred, C<T0, Ts...>, std::tuple<Tt...>, Lf, true>
   : SplitTypeList<Pred, C<Ts...>, std::tuple<Tt..., T0>, Lf>
 { };

template <template <typename> class Pred, template <typename...> class C,
          typename T0, typename ... Ts, typename Lt, typename ... Tf>
struct SplitTypeList<Pred, C<T0, Ts...>, Lt, std::tuple<Tf...>, false>
   : SplitTypeList<Pred, C<Ts...>, Lt, std::tuple<Tf..., T0>>
 { };

template <template <typename> class Pred, template <typename...> class C,
          typename ... Tt, typename ... Tf>
struct SplitTypeList<Pred, C<>, std::tuple<Tt...>, std::tuple<Tf...>, false>
 {
   using types_true  = C<Tt...>;
   using types_false = C<Tf...>;
 };

template <typename...>
struct TypeList
 { };

struct A
 { };

int main ()
 {
   using typeList = TypeList<int, double, float, A, int>;

   using splited_typeList = SplitTypeList<std::is_floating_point, typeList>;

   using float_typeList = splited_typeList::types_true;
   using other_typeList = splited_typeList::types_false;

   static_assert( std::is_same<float_typeList,
                               TypeList<double, float>>{}, "!");
   static_assert( std::is_same<other_typeList,
                               TypeList<int, A, int>>{}, "!");
 }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46852136

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档