Doing a static_assert that a template type is another template

后端 未结 3 2072
臣服心动
臣服心动 2020-11-29 04:51

How do I static_assert like this? Maybe Boost supports it if not C++ or new features in C++11?

template
struct foo {};

template

        
相关标签:
3条回答
  • 2020-11-29 05:12

    As someone else wrote,

    template<typename T, template<typename...> class TT>
    struct is_specialization_of : std::false_type { };
    
    template<template<typename...> class TT, typename... Ts>
    struct is_specialization_of<TT<Ts...>, TT> : std::true_type { };
    

    However, beware that this works only for template classes whose template parameters are all typenames! Presented with

    typedef std::array<int, 42> MyArray;
    static_assert(is_specialization_of<MyArray, std::array>::value, "");
    

    it will simply fail to compile at all.

    I believe C++11/C++14/C++17 currently have no way to deal with this limitation.

    0 讨论(0)
  • 2020-11-29 05:28

    Some small improvements over the other answers:

    • the name actually makes sense regarding the order of the parameters
    • handles const, volatile, and reference types properly via std::decay
    • implements C++14-style _v constexpr variable
    • accepts an arbitrary number of types to test against (tests for ALL)

    I have intentionally not put the std::decay_t on the is_template_for_v because a type trait should work identically regardless of whether it is called with the _v suffix or not.

    This does require C++17 for std::conjunction, but you can either remove the variadic feature or implement your own conjunction using c++11/14.

    template<template<class...> class tmpl, typename T>
    struct _is_template_for : public std::false_type {};
    
    template<template<class...> class tmpl, class... Args>
    struct _is_template_for<tmpl, tmpl<Args...>> : public std::true_type {};
    
    template<template<class...> class tmpl, typename... Ts>
    using is_template_for = std::conjunction<_is_template_for<tmpl, std::decay_t<Ts>>...>;
    
    template<template<class...> class tmpl, typename... Ts>
    constexpr bool is_template_for_v = is_template_for<tmpl, Ts...>::value;
    

    Usage:

    static_assert(is_template_for_v<std::vector, std::vector<int>>); // doesn't fire
    
    0 讨论(0)
  • 2020-11-29 05:32

    You could do something along these lines. Given a trait that can verify whether a class is an instantiation of a class template:

    #include <type_traits>
    
    template<typename T, template<typename> class TT>
    struct is_instantiation_of : std::false_type { };
    
    template<typename T, template<typename> class TT>
    struct is_instantiation_of<TT<T>, TT> : std::true_type { };
    

    Use it as follows in your program:

    template<typename T>
    struct foo {};
    
    template<typename FooType>
    struct bar {
      static_assert(is_instantiation_of<FooType, foo>::value, "failure");
    };
    
    int main()
    {
        bar<int> b; // ERROR!
        bar<foo<int>> b; // OK!
    }
    

    If you want, you could generalize this to detect whether a class is an instance of a template with any number of (type) parameters, like so:

    #include <type_traits>
    
    template<template<typename...> class TT, typename T>
    struct is_instantiation_of : std::false_type { };
    
    template<template<typename...> class TT, typename... Ts>
    struct is_instantiation_of<TT, TT<Ts...>> : std::true_type { };
    
    template<typename FooType>
    struct bar {
      static_assert(is_instantiation_of<foo, FooType>::value, "failure");
    };
    

    You would then use it this way in your program:

    template<typename FooType>
    struct bar {
      static_assert(is_instantiation_of<foo, FooType>::value, "failure");
    };
    
    int main()
    {
        bar<int> b; // ERROR!
        bar<foo<int>> b; // OK!
    }
    

    Here is a live example.

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