In C++, can you compare templates the way you can compare types?

Viewed 258

I had an idea for a template comparator analogous to std::is_same. If two templates are the same, then at least their instantiations given template arguments will be the same.

template<template<class...> class LHS, template<class..> class RHS, class... S>
using is_same_template = std::is_same<LHS<S...>, RHS<S...>>::value;

Is there a way to compare LHS and RHS without S...? I believe that without S..., the comparator would have to be instantiated over S... anyway. If they were template functions instead, I would not expect to be able to compare them, I would need to compare their instantiations. Is my intuition correct?

2 Answers

It looks like the same approach you might take with types or values works for templates. The first two lines show usage with just templates, and don't require the equals or tag functions, or any arguments to the supplied templates. The second two extract the templates from values and perform the same tests on those.

#include <iostream>

template<class...> struct A {};
template<class...> struct B {};

template<template<class...> class S>
struct Tag;

template<template<class...> class S>
struct Tag {
    template<template<class...> class T>
    constexpr auto equals(Tag<T>) -> std::false_type { return {}; }
    constexpr auto equals(Tag<S>) -> std::true_type { return {}; }
};

template<template<class...> class T, class... V>
Tag<T> tag(T<V...> const&) { return {}; }

template<class S, class T>
auto equals(S && s, T && t) -> decltype(tag(s).equals(tag(t))) { return {}; }

int main(int argc, const char *argv[]) {
    using namespace std;

    cout << Tag<A>{}.equals(Tag<A>{}) << "; " << Tag<A>{}.equals(Tag<B>{}) << endl;
    // 1; 0
    cout << Tag<B>{}.equals(Tag<A>{}) << "; " << Tag<B>{}.equals(Tag<B>{}) << endl;
    // 0; 1

    A<float> af;
    A<double> ad;
    B<int> bi;
    B<char, char> bcs;

    cout << equals(af, ad) << "; " << equals(af, bi) << endl;
    // 1; 0
    cout << equals(bi, ad) << "; " << equals(bi, bcs) << endl;
    // 0; 1

}

I had an idea for a template comparator analogous to std::is_same. [...] Is there a way to compare LHS and RHS without S...?

You can take inspiration from the "possible implementation" of std::is_same in this page and write an analogous for template-template

template <template <typename ...> class, template <typename ...> class>
struct is_tpl_same : public std::false_type
 { };

template <template <typename ...> class C>
struct is_tpl_same<C, C> : public std::true_type
 { };

You can verify that

static_assert( true  == is_tpl_same<std::set, std::set>::value, "!" );
static_assert( false == is_tpl_same<std::vector, std::set>::value, "!" );
Related