Search code examples
c++template-meta-programmingsfinaetemplate-specialization

Check with which template parameter a class was instantiated (compile time)


I try to write a metafunction type_par_same_as that selects true_type whenever the template parameter(s) of a class match the given types:

Demo

#include <type_traits>
#include <concepts>
#include <string>
#include <vector>
#include <cstdio>

template <template <typename...> class Template, typename T>
struct type_par_same_as_impl : std::false_type {};

template <template <typename...> class Template, typename... Args>
struct type_par_same_as_impl<Template<Args...>, Args...> : std::true_type {};

template <template <typename...> class Template, typename... Args>
concept type_par_same_as = type_par_same_as_impl<Template, Args...>::value;

int main()
{

    std::vector<int> vint;
    std::vector<std::string> vstring;
    if constexpr (type_par_same_as<decltype(vint), int>) {
        printf("Vector instantiated with type int!\n");
    }
}

Here's what I'm getting:

<source>:11:56: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class ...> class Template, class T> struct type_par_same_as_impl'
   11 | struct type_par_same_as_impl<Template<Args...>, Args...> : std::true_type {};
      |                                                        ^
<source>:11:56: note:   expected a class template, got 'Template<Args ...>'

My approach was that a raw template template parameter just takes in any specialization of a template, say e.g. std::vector (without type). Then I SFINAE-out class types that don't match the template specialization Template<Args...> (e.g. std::vector<int> in case int was given as Args) and I should receive true_type for all class types where this can be done. But my logic seems to be off at some point. Where did I go wrong?


Solution

  • Here's how to make it compile:

    template <class Template, typename... T>
    struct type_par_same_as_impl : std::false_type {};
    
    template <template <typename...> class Template, typename... Args>
    struct type_par_same_as_impl<Template<Args...>, Args...> : std::true_type {};
    
    template <class Template, typename... Args>
    concept type_par_same_as = type_par_same_as_impl<Template, Args...>::value;
    

    But it won't work with your test case as std::vector<int> is really std::vector<int, std::allocator<int>> and you're passing only the int of the two. So you need:

    int main()
    {
    
        std::vector<int> vint;
        std::vector<std::string> vstring;
        if constexpr (type_par_same_as<decltype(vint), int, std::allocator<int>>) {
            printf("Vector instantiated with type int!\n");
        }
    }