C ++元编程:*必须*继承抽象类的模板参数

时间:2015-10-09 08:21:21

标签: c++ templates inheritance metaprogramming

我有一个可比较的+ 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 ++中处理这种情况的正确和惯用方法是什么?谢谢!

2 个答案:

答案 0 :(得分:11)

您可以使用std::enable_if_tstd::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

Live Demo

另一种选择是使用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 ++中,虽然有一些技巧可以使用,但在有限的情况下,惯用的方法是不要打扰它。