#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");
}
I2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKbmFtZXNwYWNlIGRldGFpbAp7CiAgICAvLyBUeXBlIHJlcHJlc2VudGluZyBhIGNsYXNzIHRlbXBsYXRlIHRha2luZyBhbnkgbnVtYmVyIG9mIG5vbi10eXBlIHRlbXBsYXRlIGFyZ3VtZW50cy4KICAgIHRlbXBsYXRlIDx0eXBlbmFtZSBULCB0ZW1wbGF0ZSA8VC4uLj4gY2xhc3MgVT4KICAgIHN0cnVjdCBub250eXBlX3RlbXBsYXRlIHt9Owp9CgovLyBJZiBUIGlzIGFuIGluc3RhbnRpYXRpb24gb2YgYSBjbGFzcyB0ZW1wbGF0ZSBVIHRha2luZyBub24tdHlwZSB0ZW1wbGF0ZSBhcmd1bWVudHMsCi8vIHRoaXMgaGFzIGEgdGVzdGVkIHR5cGVkZWYgInR5cGUiIHRoYXQgaXMgYSBkZXRhaWw6Om5vbnR5cGVfdGVtcGxhdGUgcmVwcmVzZW50aW5nIFUuCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgpzdHJ1Y3Qgbm9udHlwZV90ZW1wbGF0ZV9vZiB7fTsKCi8vIFBhcnRpYWwgc3BlY2lhbGl6YXRpb25zIGZvciBhbGwgb2YgdGhlIGJ1aWx0aW4gaW50ZWdyYWwgdHlwZXMuCnRlbXBsYXRlIDx0ZW1wbGF0ZSA8Ym9vbC4uLj4gY2xhc3MgVCwgYm9vbC4uLiBWcz4Kc3RydWN0IG5vbnR5cGVfdGVtcGxhdGVfb2Y8VDxWcy4uLj4+IHsgdXNpbmcgdHlwZSA9IGRldGFpbDo6bm9udHlwZV90ZW1wbGF0ZTxib29sLCBUPjsgfTsKdGVtcGxhdGUgPHRlbXBsYXRlIDxjaGFyLi4uPiBjbGFzcyBULCBjaGFyLi4uIFZzPgpzdHJ1Y3Qgbm9udHlwZV90ZW1wbGF0ZV9vZjxUPFZzLi4uPj4geyB1c2luZyB0eXBlID0gZGV0YWlsOjpub250eXBlX3RlbXBsYXRlPGNoYXIsIFQ+OyB9Owp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHNpZ25lZCBjaGFyLi4uPiBjbGFzcyBULCBzaWduZWQgY2hhci4uLiBWcz4Kc3RydWN0IG5vbnR5cGVfdGVtcGxhdGVfb2Y8VDxWcy4uLj4+IHsgdXNpbmcgdHlwZSA9IGRldGFpbDo6bm9udHlwZV90ZW1wbGF0ZTxzaWduZWQgY2hhciwgVD47IH07CnRlbXBsYXRlIDx0ZW1wbGF0ZSA8dW5zaWduZWQgY2hhci4uLj4gY2xhc3MgVCwgdW5zaWduZWQgY2hhci4uLiBWcz4Kc3RydWN0IG5vbnR5cGVfdGVtcGxhdGVfb2Y8VDxWcy4uLj4+IHsgdXNpbmcgdHlwZSA9IGRldGFpbDo6bm9udHlwZV90ZW1wbGF0ZTx1bnNpZ25lZCBjaGFyLCBUPjsgfTsKdGVtcGxhdGUgPHRlbXBsYXRlIDxzaG9ydC4uLj4gY2xhc3MgVCwgc2hvcnQuLi4gVnM+CnN0cnVjdCBub250eXBlX3RlbXBsYXRlX29mPFQ8VnMuLi4+PiB7IHVzaW5nIHR5cGUgPSBkZXRhaWw6Om5vbnR5cGVfdGVtcGxhdGU8c2hvcnQsIFQ+OyB9Owp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHVuc2lnbmVkIHNob3J0Li4uPiBjbGFzcyBULCB1bnNpZ25lZCBzaG9ydC4uLiBWcz4Kc3RydWN0IG5vbnR5cGVfdGVtcGxhdGVfb2Y8VDxWcy4uLj4+IHsgdXNpbmcgdHlwZSA9IGRldGFpbDo6bm9udHlwZV90ZW1wbGF0ZTx1bnNpZ25lZCBzaG9ydCwgVD47IH07CnRlbXBsYXRlIDx0ZW1wbGF0ZSA8aW50Li4uPiBjbGFzcyBULCBpbnQuLi4gVnM+CnN0cnVjdCBub250eXBlX3RlbXBsYXRlX29mPFQ8VnMuLi4+PiB7IHVzaW5nIHR5cGUgPSBkZXRhaWw6Om5vbnR5cGVfdGVtcGxhdGU8aW50LCBUPjsgfTsKdGVtcGxhdGUgPHRlbXBsYXRlIDx1bnNpZ25lZCBpbnQuLi4+IGNsYXNzIFQsIHVuc2lnbmVkIGludC4uLiBWcz4Kc3RydWN0IG5vbnR5cGVfdGVtcGxhdGVfb2Y8VDxWcy4uLj4+IHsgdXNpbmcgdHlwZSA9IGRldGFpbDo6bm9udHlwZV90ZW1wbGF0ZTx1bnNpZ25lZCBpbnQsIFQ+OyB9Owp0ZW1wbGF0ZSA8dGVtcGxhdGUgPGxvbmcuLi4+IGNsYXNzIFQsIGxvbmcuLi4gVnM+CnN0cnVjdCBub250eXBlX3RlbXBsYXRlX29mPFQ8VnMuLi4+PiB7IHVzaW5nIHR5cGUgPSBkZXRhaWw6Om5vbnR5cGVfdGVtcGxhdGU8bG9uZywgVD47IH07CnRlbXBsYXRlIDx0ZW1wbGF0ZSA8dW5zaWduZWQgbG9uZy4uLj4gY2xhc3MgVCwgdW5zaWduZWQgbG9uZy4uLiBWcz4Kc3RydWN0IG5vbnR5cGVfdGVtcGxhdGVfb2Y8VDxWcy4uLj4+IHsgdXNpbmcgdHlwZSA9IGRldGFpbDo6bm9udHlwZV90ZW1wbGF0ZTx1bnNpZ25lZCBsb25nLCBUPjsgfTsKdGVtcGxhdGUgPHRlbXBsYXRlIDxsb25nIGxvbmcuLi4+IGNsYXNzIFQsIGxvbmcgbG9uZy4uLiBWcz4Kc3RydWN0IG5vbnR5cGVfdGVtcGxhdGVfb2Y8VDxWcy4uLj4+IHsgdXNpbmcgdHlwZSA9IGRldGFpbDo6bm9udHlwZV90ZW1wbGF0ZTxsb25nIGxvbmcsIFQ+OyB9Owp0ZW1wbGF0ZSA8dGVtcGxhdGUgPHVuc2lnbmVkIGxvbmcgbG9uZy4uLj4gY2xhc3MgVCwgdW5zaWduZWQgbG9uZyBsb25nLi4uIFZzPgpzdHJ1Y3Qgbm9udHlwZV90ZW1wbGF0ZV9vZjxUPFZzLi4uPj4geyB1c2luZyB0eXBlID0gZGV0YWlsOjpub250eXBlX3RlbXBsYXRlPHVuc2lnbmVkIGxvbmcgbG9uZywgVD47IH07CgovLyBBbGlhcyB0ZW1wbGF0ZSBmb3Igbm9udHlwZV90ZW1wbGF0ZV9vZi4KdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CnVzaW5nIG5vbnR5cGVfdGVtcGxhdGVfb2ZfdCA9IHR5cGVuYW1lIG5vbnR5cGVfdGVtcGxhdGVfb2Y8VD46OnR5cGU7Cgp0ZW1wbGF0ZSA8Y2xhc3MgQSwgY2xhc3MgQj4Kc3RydWN0IG1hdGNoX2NsYXNzIDogc3RkOjppc19zYW1lPG5vbnR5cGVfdGVtcGxhdGVfb2ZfdDxBPiwgbm9udHlwZV90ZW1wbGF0ZV9vZl90PEI+PiB7fTsKCnRlbXBsYXRlIDxpbnQuLi4+CnN0cnVjdCBGb297fTsKCnRlbXBsYXRlIDx1bnNpZ25lZCBsb25nLi4uPgpzdHJ1Y3QgQmFye307CgppbnQgbWFpbigpCnsKICAgIHVzaW5nIGYxID0gRm9vPDEsIDIsIDM+OwogICAgdXNpbmcgZjIgPSBGb288MT47CiAgICB1c2luZyBiMSA9IEJhcjwxLCAyLCAzPjsKICAgIHVzaW5nIGIyID0gQmFyPDE+OwogICAgc3RhdGljX2Fzc2VydChtYXRjaF9jbGFzczxmMSwgZjI+Ojp2YWx1ZSwgIkZhaWwiKTsKICAgIHN0YXRpY19hc3NlcnQobWF0Y2hfY2xhc3M8YjEsIGIyPjo6dmFsdWUsICJGYWlsIik7CiAgICBzdGF0aWNfYXNzZXJ0KCFtYXRjaF9jbGFzczxmMSwgYjE+Ojp2YWx1ZSwgIkZhaWwiKTsKfQo=