c++templatestype-traitstemplate-templatestemplate-aliases

Compare templates itselves and not instantiated template-types


My goal is to be able to compare templates i.e. write something like this

template<typename T>
struct template_type;

template<template <typename...> typename TTmpl, typename ...Ts>
struct template_type<TTmpl<Ts...>> { using type = TTmpl; }; // [1] this isn't valid C++

template<typename TRng, typename T>
auto find(TRng&& rng, const T& val)
{
    using TTmpl = typename mcu::template_type<std::remove_const_t<std::remove_reference_t<TRng>>>::type;

    if constexpr (std::is_same_v<TTmpl, std::set>) // [2] this isn't valid C++
    {
        return rng.find(val);
    }
    else
    {
        using namespace std;
        return std::find(begin(rng), end(rng), val);
    }
}

My second attemp was to use alias template and custom same function. Something like:

template<typename T>
struct template_type;

template<template <typename...> typename TTmpl, typename ...Ts>
struct template_type<TTmpl<Ts...>> { template<typename ...Us> using type = TTmpl<Us...>; };

template<template<typename...>typename T1, template<typename...> typename T2>
struct same : std::false_type {};

template<template<typename...>typename T>
struct same<T, T> : std::true_type {};

But this doesn't work either. The problem is that same<std::set, template_type<std::set<int>>::type>::value returns false, i.e. template class and it's template alias are different for some reason.

My third attemp was to write something like template_type_identity but I cannot figure out what should I use as identity:

template<template<typename...> typename T>
struct template_type_identity { using type = ???; }; // I could hardcode some constexpr ids for each template but I wanna generic solution

Solution

  • I am not sure if I understand what you want, also because I would use a different solution for your motivating case (sfinae on the presence of member find). Anyhow, this is how you can check if a given type is an instantiation of a template, provided the template has only type parameters:

    #include <iostream>
    #include <type_traits>
    #include <set>
    #include <vector>
    
    template <template<typename...> typename T, typename C>
    struct is_instantiation_of : std::false_type {};
    
    template <template<typename...> typename T,typename ...P>
    struct is_instantiation_of< T,T<P...>> : std::true_type {};
    
    int main(){
        std::cout << is_instantiation_of<std::set,std::set<int>>::value;
        std::cout << is_instantiation_of<std::set,std::vector<int>>::value;
    }
    

    Output:

    10