#include <type_traits>

namespace detail
{
    // Type representing a class template taking any number of non-type template arguments.
    template <typename T, template <T...> class U>
    struct nontype_template {};
}

// If T is an instantiation of a class template U taking non-type template arguments,
// this has a tested typedef "type" that is a detail::nontype_template representing U.
template <typename T>
struct nontype_template_of {};

// Partial specializations for all of the builtin integral types.
template <template <bool...> class T, bool... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<bool, T>; };
template <template <char...> class T, char... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<char, T>; };
template <template <signed char...> class T, signed char... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<signed char, T>; };
template <template <unsigned char...> class T, unsigned char... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<unsigned char, T>; };
template <template <short...> class T, short... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<short, T>; };
template <template <unsigned short...> class T, unsigned short... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<unsigned short, T>; };
template <template <int...> class T, int... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<int, T>; };
template <template <unsigned int...> class T, unsigned int... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<unsigned int, T>; };
template <template <long...> class T, long... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<long, T>; };
template <template <unsigned long...> class T, unsigned long... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<unsigned long, T>; };
template <template <long long...> class T, long long... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<long long, T>; };
template <template <unsigned long long...> class T, unsigned long long... Vs>
struct nontype_template_of<T<Vs...>> { using type = detail::nontype_template<unsigned long long, T>; };

// Alias template for nontype_template_of.
template <typename T>
using nontype_template_of_t = typename nontype_template_of<T>::type;

template <class A, class B>
struct match_class : std::is_same<nontype_template_of_t<A>, nontype_template_of_t<B>> {};

template <int...>
struct Foo{};

template <unsigned long...>
struct Bar{};

int main()
{
    using f1 = Foo<1, 2, 3>;
    using f2 = Foo<1>;
    using b1 = Bar<1, 2, 3>;
    using b2 = Bar<1>;
    static_assert(match_class<f1, f2>::value, "Fail");
    static_assert(match_class<b1, b2>::value, "Fail");
    static_assert(!match_class<f1, b1>::value, "Fail");
}
