Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare a template template with a template instance?

First, let me introduce you a partial solution:

template <template <class...> class,
        typename ...>
struct is_tbase_of:
  std::false_type
{ };

template <template <class...> class Type,
          typename ...Args>
struct is_tbase_of<Type, Type<Args...>>:
  std::true_type
{ };

In common cases, it works:

is_tbase_of<std::vector, std::is_integral<int>>::value; // false
is_tbase_of<std::vector, std::vector<int>>::value;      // true

But, it does not work on a «meta-returned» template template, for example:

template <template <class ...> class T>
struct quote
{
  template <typename ...U>
  using type = T<U...>;
};

using QVec =  quote<std::vector>;
is_tbase_of<QVec::template type, std::vector<int>>::value; // false...

I have tried a lot of things, trying to get the second type template arguments (to compare the quoted type specialization) but it seems I can't get them to work. Even specializing is_tbase_of for quote (which would be a less general but sufficient option) seems to send me to the black corners of template pattern-matching.

like image 628
webshinra Avatar asked Mar 04 '15 12:03

webshinra


1 Answers

You can check if you can change U<Args...> to T<Args...> and then check if the result stays the same:

#include <type_traits>
#include <vector>

struct is_tbase_of_impl
{
    struct err {};

    template <template <class...> class T, class U>
    static err test(U*);

    template <template <class...> class T, template <class...> class U, class... Args>
    static T<Args...> test(U<Args...>*);
};

template <template <class...> class T, class U>
using is_tbase_of
    = typename std::is_same< decltype(is_tbase_of_impl::test<T>((U*)0)), U >::type;

template <template <class...> class T>
struct quote
{
    template <class... U>
    using type = T<U...>;
};

using QVec = quote<std::vector>;

template <class...> struct S {};

static_assert( !is_tbase_of< std::vector, std::is_integral<int>  >::value, "" );
static_assert(  is_tbase_of< std::vector, std::vector<int>       >::value, "" );
static_assert(  is_tbase_of< QVec::type,  std::vector<int>       >::value, "" );
static_assert( !is_tbase_of< std::vector, S<int, int, int>       >::value, "" );

int main()
{
}
like image 100
Alex Avatar answered Sep 30 '22 09:09

Alex