2017-10-20 22 views
5

Trong C "hiện đại" ++, tôi có một danh sách loại:cách thanh lịch nhất để chia một C++ TypeList

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

Tôi muốn chia danh sách loại theo một vị, ví dụ std::is_floating_point. Để được chính xác hơn, đầy đủ làm việc ví dụ của tôi là:

#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>(); 
} 

in:

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âu hỏi của tôi: có bạn một ý tưởng về một giải pháp khả thi ngắn/thêm thanh lịch rằng chỉ sử dụng C + + (không có vấn đề với C + + 17) và STL? (Tôi không muốn sử dụng một lib phụ như Boost, Hana ...).

(Động lực của tôi: Tôi không muốn bỏ lỡ một hoặc hai dòng/giải pháp siêu thanh lịch, như tôi sẽ sử dụng chức năng này rộng rãi ở những nơi khác)


thực hiện hiện tại của tôi là:

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

Chỉ cần cho sự tò mò, một con trỏ lịch sử để TypeList (Andrei Alexandrescu, 1 tháng 2 năm 2002): http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813

Trả lời

4

một cái gì đó như thế này có thể hơi đơn giản hơn/ngắn

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

giải pháp rất đẹp (IMHO). Nhưng tại sao '(Bao gồm && P :: giá trị) || (! Bao gồm &&! P :: giá trị) 'và không đơn giản là' Bao gồm == P :: giá trị'? – max66

+1

@ max66 yep, điều đó đơn giản hơn, tôi chỉ ở trạng thái boolean :) đã chỉnh sửa –

+0

Tôi biết ... Tôi đang ở trong một tâm trạng lập trình mẫu meta; nhưng giải pháp của bạn đơn giản hơn rất nhiều, ngắn hơn và (IMHO) rất thanh lịch. – max66

1

Tôi không nói rằng cách sau là tốt hơn hoặc thanh lịch hơn.

Nó khác và đó là cách của tôi.

Chỉ sử dụng chuyên môn của các lớp mẫu biến thể; không có chức năng.

Nên hoạt động với C++ 11.

Hy vọng ví dụ này sẽ hữu ích.

#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>>{}, "!"); 
} 
Các vấn đề liên quan