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.
A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.
Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
There is no difference between using <typename T> OR <class T> ; i.e. it is a convention used by C++ programmers.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With