2017-06-19 55 views
1

我試圖將一個模板化方法限制爲允許的類型及其「重複」風格的給定列表。斷言是否允許使用模板參數

typedef boost::mpl::set<bool, int, double> allowedTypes; 

class Foo 
{ 
    typedef boost::mpl::set<bool, int, double> allowedTypes; 
    template<class T> 
    void some_templated_method() 
    { 
     BOOST_MPL_ASSERT((boost::mpl::has_key<allowedTypes, T>)); 
    } 
} 


// main.cpp 
Foo foo; 
struct restricted_type{}; 
foo.some_templated_method<restricted_type>(); // Compiles, why ?! 

除此之外,我想知道如何自動篩選允許類型的重複版本。對於重複的版本,我的意思是它們的std::vector<T>表示,而沒有在mpl::set

typedef boost::mpl::set<bool, 
         int, 
         double, 
         std::vector<bool>, 
         std::vector<int>, 
         std::vector<double> > allowedTypes; 
+0

我只是讓你知道我編輯我的答案有點讓類型轉換更通用。核心思想仍然是一致的,但是如果你需要,它可以讓你更靈活:) – Rerito

回答

1

您可以隨時自動創建包含原始集合及其容器包裝對象的序列。

爲此,我們需要一個一元的λ:

template <template <typename...> class Container> 
struct MakeContainerOfT { 
    template <typename T> 
    struct impl { 
     using type = Container<T>; 
    }; 
}; 

這可以處理不同的地圖(他們需要一個數值型)和數組每個集裝箱(有一個非類型模板參數)。作爲獎勵,這裏是工廠,使大小N的數組:

template <std::size_t N> 
struct ArrayOfT { 
    template <typename T> 
    struct impl { 
     using type = std::array<T, N>; 
    }; 
}; 

現在,我們需要對我們的一套適用本拉姆達(或任何其它一元拉姆達)爲我們給出任何容器的設施。

template <typename Sequence, template <typename> class Transform> 
struct TransformedSequenceBuilder { 
    using type = typename boost::mpl::reverse_fold<Sequence, 
             boost::mpl::set0<>, 
             boost::mpl::insert<boost::mpl::_1, 
                 Transform<boost::mpl::_2>>>::type; 
}; 

我們可以用「蓄壓器」,將執行此轉化lambda表達式的可變參數序列終於着手:

template <typename Sequence, template <typename> class... Transforms> 
struct MakeFullSequence; 

template <typename Sequence, template <typename> class Transform, template <typename> class... Tail> 
struct MakeFullSequence<Sequence, Transform, Tail...> { 

    using type = typename boost::mpl::reverse_fold<typename MakeFullSequence<Sequence, Tail...>::type, 
             typename TransformedSequenceBuilder<Sequence, Transform>::type, 
             boost::mpl::insert<boost::mpl::_1, boost::mpl::_2>>::type; 
}; 

template <typename Sequence> 
struct MakeFullSequence<Sequence> { 
    typedef Sequence type; 
}; 

的最後一步是定義一個別名爲您感興趣的容器:

template <typename Sequence> 
using wrapped_set = typename MakeFullSequence<Sequence, 
               ContainerOfT<std::vector>::template impl, 
               ContainerOfT<std::set>::template impl//, 
               /* any transformation you fancy here */>::type; 

爲了測試這一點,我們可以執行一個平等的測試:

using le_set = boost::mpl::set<int, double, char>; 
using le_vector_set = boost::mpl::set<std::vector<int>, std::vector<double>, std::vector<char>>; 
using le_set_set = boost::mpl::set<std::set<int>, std::set<double>, std::set<char>>; 

using le_transformed_set = wrapped_set<le_set>; 
using le_manually_transformed_set = boost::mpl::joint_view<boost::mpl::joint_view<le_set, le_set_set>::type, le_vector_set>::type; 

std::cout << boost::mpl::equal<le_transformed_set, 
           le_manually_transformed_set>::value; 

用法則非常簡單:用戶只需要提供「原始」類型集合Set每個需要它的時候,你分支的邏輯到wrapped_set<Set>

class Foo 
{ 
    typedef boost::mpl::set<bool, int, double> allowedTypes; 
    template<class T> 
    void some_templated_method() 
    { 
     BOOST_MPL_ASSERT((boost::mpl::has_key<wrapped_set<allowedTypes>, T>)); 
    } 
}; 

你可以找到演示說明我們做最後的原始集合,矢量包裝集合和集合包裝集合在這裏:Live Demo

通過該設計,您還可以添加任何其他「重複風味」,你喜歡。引用(對應const)對應的輸入類型?只需通過std::add_lvalue_reference(即std::add_const)即可!

0

我認爲正確的方法是添加自定義類型的特點應該專門有供some_templated_method支持的類型真正的價值。

#include <string> 
#include <type_traits> 
#include <vector> 

template< typename T, typename TDummy = void > class 
t_GoodForSomeTemplateMethod final 
: public ::std::integral_constant< bool, false > 
{ 
    // Nothing. 
}; 

template<> class 
t_GoodForSomeTemplateMethod<bool> final 
: public ::std::integral_constant< bool, true > 
{ 
    // Nothing. 
}; 

template< typename TInt > class 
t_GoodForSomeTemplateMethod< TInt, ::std::enable_if_t< ::std::is_integral<TInt>::value > > final 
: public ::std::integral_constant< bool, true > 
{ 
    // Nothing. 
}; 

template< typename TFlt > class 
t_GoodForSomeTemplateMethod< T, ::std::enable_if_t< ::std::is_floating_point<TFlt>::value > > final 
: public ::std::integral_constant< bool, true > 
{ 
    // Nothing. 
}; 

template< typename TItem, typename TAllocator > class 
t_GoodForSomeTemplateMethod< ::std::vector< TItem, TAllocator > > final 
: public ::std::integral_constant< bool, true > 
{ 
    // Nothing. 
}; 

template< class T > void 
SomeTemplateMethod(void) 
{ 
    static_assert(t_GoodForSomeTemplateMethod<T>::value, "type is not suitable for SomeTemplateMethod"); 
} 

int 
main(void) 
{ 
    SomeTemplateMethod<int>(); // ok 
    SomeTemplateMethod< ::std::vector<char> >(); // ok 
    SomeTemplateMethod<::std::string>(); // error 
} 
+0

這比mpl :: set方法複雜得多 – codeJack

相關問題