简体   繁体   English

如何为模板的内部类型专门化一个类?

[英]How to specialize a class for an inner type of a template?

I have a class that acts as a type trait, returning whether a certain condition is true. 我有一个充当类型特征的类,返回某个条件是否为真。 It's intended to mark classes as supporting a particular feature. 它旨在将类标记为支持特定功能。

template <typename T> struct Check : std::false_type { };

I have a template class that contains an inner class: 我有一个包含内部类的模板类:

template <unsigned N>
struct Kitty
{
  struct Purr;
};

I want to mark the inner class Purr as supporting the feature denoted as Check . 我想将内部类Purr标记为支持表示为Check的功能。 In other words, I want to make it so that Check<Kitty<123>::Purr>::value is true . 换句话说,我想使Check<Kitty<123>::Purr>::valuetrue I tried doing the following, but I get an error: 我尝试执行以下操作,但出现错误:

template <unsigned X>
struct Check<typename Kitty<X>::Purr> : std::true_type { };

error: template parameters not deducible in partial specialization: 错误:无法在部分专业化中推导模板参数:

Is it possible to accomplish this, or is it a limitation of C++ that you can't specialize on inner template class members? 是否有可能做到这一点,还是您不能专门研究内部模板类成员的C ++局限性?

This answer has an interesting approach to finding if a type exists using SFINAE. 这个答案有一种有趣的方法,可以使用SFINAE查找类型是否存在。

Adapted to check if a type T::Purr exists, it allows you to write the type trait without the problematic specialization. 适应检查类型T :: Purr是否存在,它使您可以编写类型特征而不会出现问题的专业化。

#include <type_traits>

template <unsigned T>
struct Kitty
{
    struct Purr{};
};

// A specialization without Purr, to test
template <>
struct Kitty<5>{ };

// has_purr is taken and adapted from https://stackoverflow.com/a/10722840/7359094
template<typename T>
struct has_purr
{   
    template <typename A> 
    static std::true_type has_dtor(decltype(std::declval<typename A::Purr>().~Purr())*);

    template<typename A>
    static std::false_type has_dtor(...);

    typedef decltype(has_dtor<T>(0)) type;

    static constexpr bool value = type::value;
};

// Check if a type is an instance of Kitty<T>
template<typename T>
struct is_kitty : std::false_type {};
template<unsigned T>
struct is_kitty<Kitty<T>> : std::true_type {};

template <typename T> 
struct Check : std::bool_constant< is_kitty<T>::value && has_purr<T>::value> {};

static_assert( Check<int>::value == false, "int doesn't have purr" );
static_assert( Check<Kitty<0>>::value == true, "Kitty<0> has purr" );
static_assert( Check<Kitty<5>>::value == false, "Kitty<5> doesn't has purr" );

As outlined in my comment, it is possible to make this a deduced context by using a base class, which I'll call KittyBase . 正如我的评论中概述的那样,可以通过使用基类(我称为KittyBase来将其推论为上下文。 Using a base class is actually common for templates, to avoid having unnecessary code duplicated for every new instantiation. 实际上,对于模板而言,通常使用基类,以避免为每个新实例重复不必要的代码。 We can use the same technique to get Purr without needing to deduce N . 我们可以使用相同的技术来获得Purr而无需推导N

However, simply putting Purr in the base class will remove its access to N . 但是,仅将Purr放在基类中将删除对N访问。 Fortunately, even in making Purr itself a template, this can still be a non-deduced context: Live example 幸运的是,即使将Purr本身作为模板,这仍然可以是一个非推论的上下文: 实时示例

#include <type_traits>

template <typename T> struct Check : std::false_type { };

struct KittyBase 
{    
    template<unsigned N> // Template if Purr needs N.
    struct Purr;

protected:
    ~KittyBase() = default; // Protects against invalid polymorphism.
};

template <unsigned N>
struct Kitty : private KittyBase
{
    using Purr = KittyBase::Purr<N>; // Convenience if Purr needs N.
    Purr* meow;
};

template <unsigned X>
struct Check<typename KittyBase::Purr<X>> : std::true_type { };

static_assert(not Check<int>{});
static_assert(Check<Kitty<123>::Purr>{});
static_assert(Check<Kitty<0>::Purr>{});

int main() {}

If you wish, you can even make KittyBase::Purr private and use template<typename T> friend struct Check; 如果愿意,您甚至可以将KittyBase::Purr私有,并使用template<typename T> friend struct Check; to grant access to the trait. 授予对特征的访问权限。 Unfortunately, I don't know whether you can limit that to only certain specializations of the trait. 不幸的是,我不知道您是否可以将其限制为仅该特性的某些专业化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM