C++ 元编程:*必须*继承抽象的模板参数 class
C++ meta-programming: A template parameter which *must* inherit an abstract class
我有一个摘要 class 可比较+可哈希值:
class Key
{
public:
virtual bool operator ==(const Key&) const = 0;
virtual bool operator !=(const Key&) const = 0;
virtual u32 hashcode() const = 0;
};
和一些具体的 class 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 class:
template<class T inherits Key, const T& proto> class HashSet
{
//...
};
T 是存储在这些集合中的值的类型。 proto 应该是 T 的一个实例,它被用作类型 T 的 "null" 值,用于集合包含。我对 C++ 相当有经验,但对 TMP 不是特别有经验,虽然它看起来应该非常简单,但我似乎无法弄清楚我的伪代码 "class T inherits Key" 实际上是用C++完成的。我希望能够创建一个 C 实例的哈希集,例如:
HashSet<C, C::null> myset;
有人能告诉我在 C++ 中处理这种情况的正确且惯用的方法是什么吗?谢谢!
您可以为此使用 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");
};
这可能更清楚一些,并为您提供更友好的错误消息,但您的类型约束不再在 class 声明中给出。
使用 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
{};
Can somebody please tell me what the proper and idiomatic way to handle this situation in C++ would be?
那简直就是不处理。如果用户传入从 Key
派生的类型,那么即使您没有将其作为代码注释中的显式要求添加,模板实例化也将起作用。如果用户传入无效的模板参数,那么事情就会中断。
下一个版本的 C++ 可能会支持明确包含此类注释,但在当前版本的 C++ 中,虽然您可以使用一些技巧,但在有限的情况下,惯用的方法是不要理会它。
我有一个摘要 class 可比较+可哈希值:
class Key
{
public:
virtual bool operator ==(const Key&) const = 0;
virtual bool operator !=(const Key&) const = 0;
virtual u32 hashcode() const = 0;
};
和一些具体的 class 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 class:
template<class T inherits Key, const T& proto> class HashSet
{
//...
};
T 是存储在这些集合中的值的类型。 proto 应该是 T 的一个实例,它被用作类型 T 的 "null" 值,用于集合包含。我对 C++ 相当有经验,但对 TMP 不是特别有经验,虽然它看起来应该非常简单,但我似乎无法弄清楚我的伪代码 "class T inherits Key" 实际上是用C++完成的。我希望能够创建一个 C 实例的哈希集,例如:
HashSet<C, C::null> myset;
有人能告诉我在 C++ 中处理这种情况的正确且惯用的方法是什么吗?谢谢!
您可以为此使用 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");
};
这可能更清楚一些,并为您提供更友好的错误消息,但您的类型约束不再在 class 声明中给出。
使用 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
{};
Can somebody please tell me what the proper and idiomatic way to handle this situation in C++ would be?
那简直就是不处理。如果用户传入从 Key
派生的类型,那么即使您没有将其作为代码注释中的显式要求添加,模板实例化也将起作用。如果用户传入无效的模板参数,那么事情就会中断。
下一个版本的 C++ 可能会支持明确包含此类注释,但在当前版本的 C++ 中,虽然您可以使用一些技巧,但在有限的情况下,惯用的方法是不要理会它。