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

时间:2017-01-19 21:38:57

标签: c++ templates partial-specialization

我有一个充当类型特征的类,返回某个条件是否为真。它旨在将类标记为支持特定功能。

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

我有一个包含内部类的模板类:

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

我想将内部类Purr标记为支持表示为Check的功能。换句话说,我想这样做Check<Kitty<123>::Purr>::valuetrue。我尝试了以下操作,但是我收到了一个错误:

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

错误:模板参数在部分专业化中无法推导:

是否有可能实现这一目标,还是C ++的限制,你不能专注于内部模板类成员?

2 个答案:

答案 0 :(得分:1)

This answer有一种有趣的方法来查找是否存在使用SFINAE的类型。

适用于检查类型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" );

答案 1 :(得分:1)

正如我的评论中所述,可以通过使用基类来将其作为推断的上下文,我将其称为KittyBase。对于模板,使用基类实际上是常见的,以避免为每个新实例化重复不必要的代码。我们可以使用相同的技术获取Purr,而无需推断N

但是,只需将Purr放在基类中即可删除对N的访问权限。幸运的是,即使将Purr本身作为模板,这仍然可以是非推断的上下文: Live example

#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() {}

如果您愿意,您甚至可以将KittyBase::Purr设为私有,并使用template<typename T> friend struct Check;授予对该特征的访问权限。不幸的是,我不知道你是否可以将其仅限于特质的某些特化。