'In C++ template meta programming, how do you return a template parameter?

template <template <typename...> typename T, template <typename...> typename U>
struct is_same_template : std::false_type {};

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

template <template <typename...> typename T, template <typename...> typename U>
constexpr bool is_same_template_v = is_same_template<T, U>::value;

The above implementation of is_same_template can cause the two statements below to compile.

static_assert(is_same_template_v<std::map, std::map>);
static_assert(!is_same_template_v<std::map, std::vector>);

Is it possible to enhance the is_same_template such that the following statements will compile?

static_assert(is_same_template_v<std::map<int, bool>, std::map>);
static_assert(is_same_template_v<std::map<int, bool>, std::map<int, int>>);
static_assert(!is_same_template_v<std::map<int, bool>, std::vector>);
static_assert(!is_same_template_v<std::map<int, bool>, std::vector<int>>);


Solution 1:[1]

Since the template parameter of the template class is fixed, you cannot define a template class that is also named is_same_template but accepts different template parameters, instead, you need to redefine the template class but reuse is_same_template, that is, use template partial specialization to get the template template parameter and pass it to is_same_template.

template <typename T, typename U>
struct is_same_template2 : std::false_type {};

template<
  template <typename...> typename T, typename... TArgs,
  template <typename...> typename U, typename... UArgs>
struct is_same_template2<T<TArgs...>, U<UArgs...>> : is_same_template<T, U> {};

template <typename T, template <typename...> typename U>
struct is_same_template3 : std::false_type {};

template <
  template <typename...> typename T, typename... TArgs,
  template <typename...> typename U>
struct is_same_template3<T<TArgs...>, U> : is_same_template<T, U> {};

In order to unify the interface, you can overload different template functions and use the corresponding implementation

template <template <typename...> typename T, template <typename...> typename U>
constexpr bool same_template() {
  return is_same_template<T, U>();
}

template <typename T, typename U>
constexpr bool same_template() {
  return is_same_template2<T, U>();
}

template <typename T, template <typename...> typename U>
constexpr bool same_template() {
  return is_same_template3<T, U>();
}

Then you can invoke like this

static_assert(same_template<std::map, std::map>());
static_assert(!same_template<std::map, std::vector>());
static_assert(same_template<std::map<int, bool>, std::map>());
static_assert(same_template<std::map<int, bool>, std::map<int, int>>());
static_assert(!same_template<std::map<int, bool>, std::vector>());
static_assert(!same_template<std::map<int, bool>, std::vector<int>>());

Demo

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1