2017-10-20 15 views
5

विभाजित करने के लिए "आधुनिक" सी ++ में जिस तरह से, मैं एक प्रकार सूची है। अधिक सटीक होना, मेरा पूरा काम कर उदाहरण है:सबसे सुरुचिपूर्ण एक सी ++ TypeList

#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>] 

मेरे सवाल: यदि आप एक संभव छोटी/अधिक सुरुचिपूर्ण समाधान की एक विचार है कि केवल सी ++ का उपयोग करता है (सी ++ 17 के साथ कोई समस्या नहीं) और एसटीएल? (मैं बूस्ट, हाना जैसे सहायक lib का उपयोग नहीं करना चाहता ...)।

(मेरे प्रेरणा: मैं, एक एक या दो पंक्तियों/सुपर सुरुचिपूर्ण समाधान याद आती है के रूप में मैं अन्य स्थानों में बड़े पैमाने पर इस कार्यक्षमता का उपयोग होगा नहीं करना चाहती)


मेरे वर्तमान कार्यान्वयन है:

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, फरवरी 01, 2002) के लिए एक ऐतिहासिक सूचक: http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813

उत्तर

4

कुछ इस तरह कुछ हद तक सरल/कम

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

बहुत अच्छा समाधान (IMHO) हो सकता है। लेकिन क्यों '(शामिल करें & पी :: मूल्य) || (! शामिल करें &&! पी :: मूल्य) 'और न केवल' शामिल करें == पी :: मूल्य'? – max66

+1

@ max66 हाँ, यह आसान है, मैं बस एक बूलियन केवल मूड में था :) संपादित –

+0

मुझे पता है ... मैं टेम्पलेट मेटा प्रोग्रामिंग केवल मूड में हूं; लेकिन आपका समाधान बहुत सरल, छोटा और (आईएमएचओ) बहुत ही सुरुचिपूर्ण है। – max66

1

मैं नहीं कहता कि निम्न तरीका बेहतर या अधिक सुरुचिपूर्ण है।

यह अलग है और यह मेरा तरीका है।

विविधता टेम्पलेट कक्षाओं के केवल विशेषज्ञता का उपयोग करना; कोई कार्य नहीं।

सी ++ 11 के साथ भी काम करना चाहिए।

आशा है कि यह उदाहरण मदद करता है।

#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>>{}, "!"); 
} 
संबंधित मुद्दे