断言是否允许模板参数
Assert if template parameter is allowed
我正在尝试将模板化方法限制为给定的允许类型列表及其 "repeated" 风格。
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;
我认为正确的方法是添加自定义类型特征,该特征应该专门为 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
}
您始终可以自动创建一个序列,其中包括原始集合及其容器包装的对应序列。
为此我们需要一个一元 lambda:
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>;
};
};
现在,我们需要一个工具来将这个 lambda(或任何其他一元 lambda)应用到我们给定的任何容器的集合上。
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;
};
我们终于可以继续 "accumulator",它将对转换 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;
用法非常简单:用户只提供 "raw" 类型集 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
使用该设计,您还可以添加您喜欢的任何其他 "repeated flavour"。输入类型的引用(resp. const
)对应物?只需传入 std::add_lvalue_reference
(resp. std::add_const
)!
我正在尝试将模板化方法限制为给定的允许类型列表及其 "repeated" 风格。
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;
我认为正确的方法是添加自定义类型特征,该特征应该专门为 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
}
您始终可以自动创建一个序列,其中包括原始集合及其容器包装的对应序列。
为此我们需要一个一元 lambda:
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>;
};
};
现在,我们需要一个工具来将这个 lambda(或任何其他一元 lambda)应用到我们给定的任何容器的集合上。
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;
};
我们终于可以继续 "accumulator",它将对转换 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;
用法非常简单:用户只提供 "raw" 类型集 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
使用该设计,您还可以添加您喜欢的任何其他 "repeated flavour"。输入类型的引用(resp. const
)对应物?只需传入 std::add_lvalue_reference
(resp. std::add_const
)!