我有一个可比较的+ hashable值的抽象类:
class Key
{
public:
virtual bool operator ==(const Key&) const = 0;
virtual bool operator !=(const Key&) const = 0;
virtual u32 hashcode() const = 0;
};
和一些具体的C类继承了这个。
class C : public Key
{
private:
u32 a, b;
public:
static const C& null; // a prototype for representing a "no value" C
// Some reasonable implementation; it's just a pair
// ...
};
我想实现一个模板化的HashSet类:
template<class T inherits Key, const T& proto> class HashSet
{
//...
};
T是存储在这些集合中的值的类型。 proto应该是T的一个实例,它被用作类型T的“null”值,用于集合包含。我对C ++有相当的经验,但对TMP并不是特别有用,虽然它看起来像是一件令人尴尬的简单易事,我似乎无法弄清楚像我的伪代码“T类继承Key”< / strong>实际上是用C ++完成的。我希望能够创建一个C实例的哈希集,如:
HashSet<C, C::null> myset;
有人可以告诉我在C ++中处理这种情况的正确和惯用方法是什么?谢谢!
答案 0 :(得分:11)
您可以使用std::enable_if_t
和std::is_base_of
:
template<class T, const T& proto,
std::enable_if_t<std::is_base_of<Key,T>::value>* = nullptr>
class HashSet
{
//...
};
现在HashSet
实例仅在T
继承自Key
后有效。
std::enable_if_t
是C ++ 14的一项功能。如果您遇到C ++ 11,可以使用typename std::enable_if<...>::type
。
另一种选择是使用static_assert
:
template<class T, const T& proto>
class HashSet
{
static_assert(std::is_base_of<Key, T>::value, "T must inherit from Key");
};
这可能会更清晰一些,并为您提供更友好的错误消息,但您的类型约束不再在类声明中给出。
使用Concepts,我们将获得清晰,更好的错误消息并在声明中保留我们的约束:
template <class Base, class Derived>
concept bool IsBaseOf = std::is_base_of<Base, Derived>::value;
template<class T, const T& proto>
requires IsBaseOf<Key,T>
class HashSet
{};
答案 1 :(得分:2)
有人可以告诉我在C ++中处理这种情况的恰当和惯用方法是什么?
那根本就不会处理它。如果用户传入的类型派生自Key
,那么即使您没有将其作为代码注释中的显式要求添加,模板实例化也会起作用。如果用户传入了无效的模板参数,那么事情就会破裂。
下一版本的C ++可能会支持清楚地包含这样的注释,但在当前版本的C ++中,虽然有一些技巧可以使用,但在有限的情况下,惯用的方法是不要打扰它。