如何将 class 专门化为模板的内部类型?
How to specialize a class for an inner type of a template?
我有一个 class 作为类型特征,返回某个条件是否为真。它旨在将 classes 标记为支持特定功能。
template <typename T> struct Check : std::false_type { };
我有一个模板 class,其中包含一个内部 class:
template <unsigned N>
struct Kitty
{
struct Purr;
};
我想将内部 class Purr
标记为支持表示为 Check
的功能。换句话说,我想让 Check<Kitty<123>::Purr>::value
变成 true
。我尝试执行以下操作,但出现错误:
template <unsigned X>
struct Check<typename Kitty<X>::Purr> : std::true_type { };
error: template parameters not deducible in partial specialization:
是否有可能实现这一点,或者这是 C++ 的限制,您不能专注于内部模板 class 成员?
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
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" );
正如我的评论中所述,可以通过使用基数 class 将其作为推导上下文,我将其称为 KittyBase
。使用基 class 实际上对于模板来说很常见,以避免为每个新实例重复不必要的代码。我们可以使用相同的技术得到 Purr
而无需推导出 N
.
但是,只需将 Purr
放入基数 class 中即可移除其对 N
的访问权限。幸运的是,即使使 Purr
本身成为模板,这仍然可以是 non-deduced 上下文: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;
授予对该特征的访问权限。不幸的是,我不知道你是否可以将其限制为仅限于特征的某些专业化。