How to tell if template type is an instance of a template class?

前端 未结 3 1466
南旧
南旧 2021-01-19 02:41

I have a function that takes a template type to determine a return value. Is there any way to tell at compile time if the template type is some instantiation of a template c

相关标签:
3条回答
  • 2021-01-19 03:16

    Here's an option:

    #include <iostream>
    #include <type_traits>
    #include <string>
    
    template <class, template <class> class>
    struct is_instance : public std::false_type {};
    
    template <class T, template <class> class U>
    struct is_instance<U<T>, U> : public std::true_type {};
    
    template <class>
    class Second 
    {};
    
    int main()
    {
        using A = Second<int>;
        using B = Second<std::string>;
        using C = float;
        std::cout << is_instance<A, Second>{} << '\n'; // prints 1
        std::cout << is_instance<B, Second>{} << '\n'; // prints 1
        std::cout << is_instance<C, Second>{} << '\n'; // prints 0
    }
    

    It's basically specializing the is_instance struct for types that are instantiations of a template.

    0 讨论(0)
  • 2021-01-19 03:18

    Yet another improvement to the answer of @RichardHodges: Usually, one also wants to capture not only plain types, but rather all cv-qualified and ref-qualified types.

    Put differently, if is_instance<A, Second>{} is true, also is_instance<A const&, Second>{} or is_instance<A&&, Second>{} should be true. The current implementations in this thread don't support that.

    The following code accounts for all cv-ref-qualified types, by adding another indirection and a std::decay_t:

    namespace
    {
        template <typename, template <typename...> typename>
        struct is_instance_impl : public std::false_type {};
    
        template <template <typename...> typename U, typename...Ts>
        struct is_instance_impl<U<Ts...>, U> : public std::true_type {};
    }
    
    template <typename T, template <typename ...> typename U>
    using is_instance = is_instance_impl<std::decay_t<T>, U>;
    

    Use it as

    #include <iostream>
    
    template <typename ...> struct foo{};
    template <typename ...> struct bar{};
    
    int main()
    {
        std::cout << is_instance<foo<int>, foo>{} << std::endl;           // prints 1
        std::cout << is_instance<foo<float> const&, foo>{} <<std::endl;   // prints 1
        std::cout << is_instance<foo<double,int> &&, foo>{} << std::endl; // prints 1
        std::cout << is_instance<bar<int> &&, foo>{} << std::endl;        // prints 0
    }
    
    0 讨论(0)
  • 2021-01-19 03:21

    Another option, picking up on Henri's comment:

    #include <iostream>
    #include <type_traits>
    #include <string>
    
    template <class, template <class, class...> class>
    struct is_instance : public std::false_type {};
    
    template <class...Ts, template <class, class...> class U>
    struct is_instance<U<Ts...>, U> : public std::true_type {};
    
    template <class>
    class Second 
    {};
    
    template <class, class, class>
    class Third 
    {};
    
    int main()
    {
        using A = Second<int>;
        using B = Second<std::string>;
        using C = float;
        using D = Third<std::string, int, void>;
        std::cout << is_instance<A, Second>{} << '\n'; // prints 1
        std::cout << is_instance<B, Second>{} << '\n'; // prints 1
        std::cout << is_instance<C, Second>{} << '\n'; // prints 0
        std::cout << is_instance<D, Third>{} << '\n'; // prints 1
    }
    
    0 讨论(0)
提交回复
热议问题