Sebastian.M
Sebastian.M

Reputation: 676

Testing if two templates are the same, even with non-type parameter packs as parameters

So I need to find out if two templates are the same, even if the parameters are not, ie. if in T<A> and U<B> T and U are the same, even if A and B are not. std::is_same can't be used, as it only regards the full type.

My first solution was this:

template<typename T, typename U>
struct is_same_template : std::false_type {};

template<template<typename> typename T, typename A, typename B>
struct is_same_template<T<A>, T<B>> : std::true_type {};

template<template<typename> typename T, typename A, template<typename> typename U, typename B>
struct is_same_template<T<A>, U<B>> : std::false_type {};

It works, but only for templates with one parameter, so I extended it to:

template<typename T, typename U>
struct is_same_template : std::false_type {};

template<template<typename...> typename T, typename... A, typename... B>
struct is_same_template<T<A...>, T<B...>> : std::true_type {};

template<template<typename...> typename T, typename... A, template<typename...> typename U, typename... B>
struct is_same_template<T<A...>, U<B...>> : std::false_type {};

That works great, even for templates with parameter packs.
Example:

template <typename... Params>
struct Test1 {};

template <typename... Params>
struct Test2 {};

struct Foo {};
struct Bar {};

int main(int argc, char** argv) {    
    std::cout << std::boolalpha;
    std::cout << is_same_template<Test1<Foo>, Test2<Foo>>::value << '\n';
    std::cout << is_same_template<Test1<Foo>, Test2<Bar>>::value << '\n';
    std::cout << is_same_template<Test1<Foo, Bar>, Test2<Bar>>::value << '\n';

    std::cout << is_same_template<Test1<Foo>, Test1<Foo>>::value << '\n';
    std::cout << is_same_template<Test1<Foo>, Test1<Bar>>::value << '\n';
    std::cout << is_same_template<Test1<Foo, Bar>, Test1<Bar>>::value << '\n';

    return 0;
}

Output:

false
false
false
true
true
true

My problem is that in the actual use case I did this for the template parameter is an int parameter pack:

template <int... Indexes>
struct ArgIndexes {};

I didn't know that types and non-types are handled differently. When testing with ArgIndexes the result was always the value of

template<typename T, typename U>
struct is_same_template : std::false_type {};

Is there any way to get this to work with both type and non-type parameter packs without handling every kind of non-type parameter pack specifically?

EDIT

I just realized that

template<template<typename...> typename T, typename... A, template<typename...> typename U, typename... B>
struct is_same_template<T<A...>, U<B...>> : std::false_type {};

is redundant and can be removed.

Upvotes: 8

Views: 274

Answers (2)

Sebastian.M
Sebastian.M

Reputation: 676

So auto works. All my tests worked with this combination:

template<typename T, typename U>
struct is_same_template : std::false_type {};

template<template<typename...> typename T, typename... A, typename... B>
struct is_same_template<T<A...>, T<B...>> : std::true_type {};

template<template<auto...> typename T, auto... A, auto... B>
struct is_same_template<T<A...>, T<B...>> : std::true_type {};

I didn't test auto before because the Clang integrated into my IDE told me that auto is not allowed. Well, it is, and it works. Thanks @Jarod42 for making me reconsider it.

Upvotes: 2

Caleth
Caleth

Reputation: 63277

If you only want to check templates with a single pack of value parameters, you can add this specialization:

template<typename A, template<A...> typename T, A... X, A... Y>
struct is_same_template<T<X...>, T<Y...>> : std::true_type {};

Used like:

template <int... Params>
struct Test1 {};

template <char... Params>
struct Test2 {};

int main(int argc, char** argv) {    
    std::cout << std::boolalpha;
    std::cout << is_same_template<Test1<1, 2, 3>, Test2<1, 2, 3>>::value << '\n';
    std::cout << is_same_template<Test1<1>, Test2<2>>::value << '\n';
    std::cout << is_same_template<Test1<1, 2>, Test2<2>>::value << '\n';

    std::cout << is_same_template<Test1<1>, Test1<1>>::value << '\n';
    std::cout << is_same_template<Test1<1>, Test1<2>>::value << '\n';
    std::cout << is_same_template<Test1<1, 2>, Test1<2>>::value << '\n';

    return 0;
}

Live on Wandbox

Upvotes: 1

Related Questions