我想知道是否有任何解决方案可以找到一个类型是否是一个模板的特化,它采用非类型参数而不指定每个类型?
例如,如果有这样的类:
template<typename T, std::size_t R>
struct F {}
目前,我使用的是非常专业的特征:
template<template<typename, std::size_t> class TT, typename T>
struct is_2 : std::false_type { };
template<template<typename, std::size_t> class TT, typename V1, std::size_t R>
struct is_2<TT, TT<V1, R>> : std::true_type { };
并像is_2<F, T>::value
一样使用。但是,这是不实际的,因为如果添加另一个模板参数,则必须编辑特征。此外,如果您有多个此类模板,则需要为每个模板编写特征。
有没有办法让事情变得更实用?我可以使用C ++ 14。我并不是指使用宏来减少代码量。
答案 0 :(得分:8)
非类型模板参数有点像红头的继子。
没有&#34;任何模板参数匹配,是否匹配&#34;。
如果您可以修改F
,则可以通过将常量包装在精简类型中来使其更加统一。所以:
template<typename T, class R>
struct F;
template<typename T, std::size_t R>
struct F<T, std::integral_constant<std::size_t, R>> {};
现在可以统一编写像is
这样的元程序:
template<template<class...>class Template, class T>
struct is_instantiation : std::false_type {};
template<template<class...>class Template, class... Ts>
struct is_instantiation<Template, Template<Ts...>> : std::true_type {};
匹配所有内容。
如果你对F
的控制较少,你可以使用你的方法,或编写将template
和template
的实例同时提升到带有类型包装器的东西的元程序。
struct meta_F {
template<class T, std::size_t R>using raw_apply=F<T,R>;
template<class T, class R>using apply=raw_apply<T,R::value_type>;
};
template<class meta_Template, class... Args>
struct type_lifted_template {};
template<class T, std::size_t R>
struct type_lifted_template< meta_F, T, std::integral_constant<std::size_t, R> > {
using result = meta_F::template raw_apply<T, R>;
};
template<class T, std::size_t R>
auto type_lift_instance( F<T,R> )
-> type_lifted_template< meta_F, T, std::integral_constant<std::size_t, R> >;
现在,type_lift_instance
可以专门用于多种类型,并且可以使用一些decltype
魔法来提取不同类型的type_lifted_template
专精。
所有这些都非常粗糙。如果你在模板上进行大量的元编程,那么你最好是让模板采用统一的类型参数,而不是搞乱这些东西。
template<class meta_F, class C>
struct meta_template_is_lifted : std::false_type {};
template<class meta_F, class...Ts>
struct meta_template_is_lifted<meta_F, type_lifted_template< meta_F, Ts... >> : std::true_type {};
template<class meta_F, class C>
struct meta_template_is : meta_template_is_lifted< meta_F, decltype(type_lift_instance( std::declval<C>() ) ) > {};
这并不是更少的输入,但是元化远离is
代码(或其他类似的代码)。
我可能正在使用&#34; lift&#34;不正确。
答案 1 :(得分:4)
如果你可以修改F
并且没有其他限制你没有提到,最简单的解决方案是添加一个独特的基类:
#include <cstddef>
#include <type_traits>
struct unique_F_base {};
template<typename T, std::size_t R>
struct F : unique_F_base
{
};
template<typename T>
using is_F = std::is_base_of<unique_F_base,T>;
int main()
{
static_assert( !is_F< int >::value, "Oops" );
static_assert( is_F< F<int,42> >::value, "Oops" );
}