2017-06-19 62 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