c++ - 拆分 C++ TypeList 的最优雅方式

标签 c++ c++11 metaprogramming c++17

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

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

我想根据谓词拆分类型列表,例如 std::is_floating_point .更准确地说,我的完整工作 例子是:
#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>();
}

打印:
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 之类的辅助库……)。

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

我目前的实现是:
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 的历史指针(Andrei Alexandrescu,2002 年 2 月 1 日):http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813

最佳答案

这样的事情可能会更简单/更短

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<>{} ));
};

关于c++ - 拆分 C++ TypeList 的最优雅方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46852136/

相关文章:

c++ - gcc编译的二进制文件大小不同?

c++ - 逻辑错误。 std::string 中的元素未被 for 循环正确替换

R - 如何从表达式中提取对象名称

c++ - 另一个 vector 与动态分配的数组

c++ - std::thread 完成函数

ruby-on-rails - Rails Workflow Gem - 将事件元编程到named_scopes?

python - 使用 type() 手动创建新类时,子类 __module__ 设置为元类模块

c++ - C++中的字符比较

c++ - lambda 中引用捕获对象的类型

c++ - return {} 和 return Object{} 之间的区别