Как я могу проверить, является ли тип экземпляром данного шаблона класса? - программирование

Как я могу проверить, является ли тип экземпляром данного шаблона класса?

Можно ли проверить, что тип является экземпляром конкретного шаблона?

У меня есть шаблон класса, где один из параметров шаблона должен быть либо экземпляром конкретного шаблона, либо каким-либо другим типом. Например, рассмотрите это простое определение списка типов:

struct null_type;

template <typename Head, typename Tail>
struct typelist
{
    // Tail must be a typelist or null_type

    typedef Head head;
    typedef Tail tail;
};

Теперь я хотел бы убедиться, что тип, указанный для параметра шаблона Tail, всегда является экземпляром typelist или null_type. Я мог бы использовать частичную специализацию для определения шаблона только для этих случаев, например:

template <typename Head, typename Tail>
struct typelist; // default, not defined

template <typename Head, typename H, typename T>
struct typelist< Head, typelist<H,T> > // Tail = typelist, ok
{
    typedef Head head;
    typedef typelist<H,T> tail;
};

template <typename Head>
struct typelist< Head, null_type > // Tail = null_type, ok
{
    typedef Head head;
    typedef null_type tail;
};

Однако я в конечном итоге дублирую код, чего я бы хотел избежать. В идеале мне нужна черта, чтобы проверить, является ли тип экземпляром шаблона, использовать его с помощью enable_if или в статических утверждениях:

#include <boost/mpl/or.hpp>
#include <type_traits>

struct null_type;

template <typename Head, typename Tail>
struct typelist
{
    static_assert(
        boost::mpl::or_<
            is_instantiation_of< typelist, Tail >,
            std::is_same< Tail, null_type >
        >::value,
        "Tail must be a typelist or null_type" );

    typedef Head head;
    typedef Tail tail;
};

Является ли такой признак (is_instantiation_of) уже доступным в стандартной библиотеке или в Boost? Можно ли написать один?

4b9b3361

Ответ 1

Я придумал следующее решение, используя вариативные шаблоны С++ 11 и простую частичную специализацию:

#include <type_traits>

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

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

Он может быть адаптирован к С++ 03, используя препроцессор для генерации версий для различного количества параметров шаблона, но, возможно, более простой способ.