How to test if type is specialization of template with non-type parameters?

前端 未结 2 1804
眼角桃花
眼角桃花 2021-01-02 09:26

I was wondering if there was any solution to find if a type was a specialization of a template that takes non-type parameters without specifying every type ?

For ins

相关标签:
2条回答
  • 2021-01-02 09:35

    If you can modify F and there are no other restrictions you haven't mentioned, the easiest solution would be to add a unique base class:

    #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" );
    }
    
    0 讨论(0)
  • 2021-01-02 09:44

    Non-type template parameters are a bit of a red headed stepchild.

    There is no "any template parameter is matched, type or not".

    If you can modify F, you make it more uniform by wrapping your constants in thin types. So:

    template<typename T, class R>
    struct F;
    
    template<typename T, std::size_t R>
    struct F<T, std::integral_constant<std::size_t, R>> {};
    

    now meta-programs like is can be written uniformly:

    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 {};
    

    matching everything.

    If you have less control over F, you can either use your approach, or write metaprogram that hoists both a template and an instance of that template into something with type wrappers.

    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> >;
    

    Now, type_lift_instance can be specialized for multiple types, and some decltype magic could be used to extract the type_lifted_template specialization for different types.

    All of this is pretty rough. You'd be best, if you are doing lots of meta programming on templates, to just have your templates take uniform type parameters, instead of messing around with this stuff.

    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>() ) ) > {};
    

    this isn't much less typing, but the metafication goes on far away from the is code (or other similar code).

    I'm probably using "lift" incorrectly.

    0 讨论(0)
提交回复
热议问题