Search code examples
c++c++14variadic-templatescomparatortemplate-templates

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


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?


Solution

  • 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
    
    }