Подтвердить что ты не робот

Является ли 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?

4b9b3361

Ответ 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)
{
  // ...
}