如何检查一个类型是否是给定类模板的实例化?

17

有没有办法检查一个类型是否是特定模板的实例化?

我有一个类模板,其中一个模板参数必须是特定模板的实例化或其他类型。例如,考虑这个简单的类型列表定义:

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;
};

然而,我最终会重复代码,这是我想避免的。理想情况下,我需要一个trait来测试类型是否是模板的实例化,以便在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;
};

在标准库或Boost中是否已经存在这样的特性(is_instantiation_of)?能否自己编写一个?

1个回答

25
我想出了以下解决方案,使用C++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 {};

可以通过使用预处理器为不同数量的模板参数生成版本来将其适应于C++03,但也许有一种更简单的方法。


Tch,我正要点击“发布你的答案”呢。:P - Xeo
5
顺便说一下,我将我的版本称为“is_specialization_of”,因为这是正确的术语。 “实例化”是生成“特化”的过程。 - R. Martinho Fernandes
1
@Xeo:那个不一致的! :P - R. Martinho Fernandes
7
注意,如果 Template 参数是一个具有非类型参数的模板,例如 template<class T, int I> struct foo{...}(适用于 gcc 4.7),则该解决方案会出现错误。 - Mike Kinghan
2
无法在std::array和所有这类模板中工作 - 请参见先前的评论 - PiotrNycz
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接