Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

templates

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.

like image 531
Sebastian.M Avatar asked Oct 04 '17 08:10

Sebastian.M


People also ask

Can we use non-type parameters as argument templates?

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 the non-type templates?

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.

Can a template be a template parameter?

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.)

What is the difference between Typename and class in template?

There is no difference between using <typename T> OR <class T> ; i.e. it is a convention used by C++ programmers.


2 Answers

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.

like image 61
Sebastian.M Avatar answered Nov 10 '22 02:11

Sebastian.M


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

like image 25
Caleth Avatar answered Nov 10 '22 02:11

Caleth