Matching variadic non-type templates

Viewed 1393

Let's say I have two structs, Foo and Bar:

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

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

I want to create a type trait (call it match_class) that returns true if I pass two Foo<...> types or two Bar<...> types, but false if I try to mix them:

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");
}

For C++1z (clang 5.0.0 and gcc 8.0.0) it's sufficient to do this (Demo):

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

template<class T, template<T...> class S, T... U, T... V>
struct match_class<S<U...>, S<V...>> : std::true_type{};

But in C++14 I get the following error (same compilers* Demo):

error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used [-Wunusable-partial-specialization]
struct match_class<S<U...>, S<V...>> : std::true_type{};
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: non-deducible template parameter 'T'
template<class T, template<T...> class S, T... U, T... V>

Question: What is a workaround for this in C++14?

Ideally the syntax for testing the type trait should remain the same.

Secondary question: Is the behavior for C++14 correct? (or alternatively is the behavior I see for C++17 unspecified?)

*Note that MSVC 19.00.23506 has the same kind of failure Demo

3 Answers
Related