Является ли T экземпляром шаблона в С++?
Предположим, что я в шаблоне, и я хочу знать, является ли параметр типа T экземпляром конкретного шаблона, например std::shared_ptr
:
template<typename T>
void f(T&& param)
{
if (instantiation_of(T, std::shared_ptr)) ... // if T is an instantiation of
// std::shared_ptr...
...
}
Скорее всего, я хочу сделать этот тест как часть теста std:: enable_if:
template<typename T>
std::enable_if<instantiation_of<T, std::shared_ptr>::type
f(T&& param)
{
...
}
// other overloads of f for when T is not an instantiation of std::shared_ptr
Есть ли способ сделать это? Обратите внимание, что решение должно работать со всеми возможными типами и шаблонами, в том числе в стандартной библиотеке и в других библиотеках, которые я не могу изменить. Мое использование std::shared_ptr
выше - всего лишь пример того, что я могу сделать.
Если это возможно, как мне самому написать тест, т.е. реализовать instantiation_of
?
Ответы
Ответ 1
Частичная спецификация должна быть в состоянии сделать это.
template <template <typename...> class X, typename T>
struct instantiation_of : std::false_type {};
template <template <typename...> class X, typename... Y>
struct instantiation_of<X, X<Y...>> : std::true_type {};
http://ideone.com/4n346
Мне действительно пришлось искать синтаксис шаблона шаблона, потому что у меня в принципе никогда не было причин использовать его раньше.
Не знаете, как это взаимодействует с шаблонами типа std::vector
с дополнительными аргументами по умолчанию.
Ответ 2
Зачем использовать enable_if
, когда достаточно простой перегрузки?
template<typename T>
void f(std::shared_ptr<T> param)
{
// ...
}
Если вам действительно нужна такая черта, я думаю, что вам нужно начать (только грубо протестировано с VС++ 2010):
#include <type_traits>
template<typename>
struct template_arg;
template<template<typename> class T, typename U>
struct template_arg<T<U>>
{
typedef U type;
};
template<typename T>
struct is_template
{
static T* make();
template<typename U>
static std::true_type check(U*, typename template_arg<U>::type* = nullptr);
static std::false_type check(...);
static bool const value =
std::is_same<std::true_type, decltype(check(make()))>::value;
};
template<
typename T,
template<typename> class,
bool Enable = is_template<T>::value
>
struct specialization_of : std::false_type
{ };
template<typename T, template<typename> class U>
struct specialization_of<T, U, true> :
std::is_same<T, U<typename template_arg<T>::type>>
{ };
Ответ 3
Лучший способ сделать это при работе с T && заключается в том, чтобы убедиться, что вы удалили ошибку перед выполнением проверки, потому что базовый тип T может быть ссылкой или типом значения, а частичная специализация шаблона должна быть точной для работы. В сочетании с ответом над кодом для этого может быть:
template <
typename T,
template <typename...> class Templated
> struct has_template_type_impl : std::false_type {};
template <
template <typename...> class T,
typename... Ts
> struct has_template_type_impl<T<Ts...>, T> : std::true_type {};
template <
typename T,
template <typename...> class Templated
> using has_template_type = has_template_type_impl<
typename std::remove_reference<T>::type,
Templated
>;
И тогда вы просто включаете свой путь к победе:
template <typename T>
typename std::enable_if<has_template_type<T, std::shared_ptr>::value>::type
f(T&& param)
{
// ...
}