I have an abstract class for comparable+hashable values:
class Key
{
public:
virtual bool operator ==(const Key&) const = 0;
virtual bool operator !=(const Key&) const = 0;
virtual u32 hashcode() const = 0;
};
and some concrete class C which inherits this.
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
// ...
};
and I would like to implement a templated HashSet class:
template<class T inherits Key, const T& proto> class HashSet
{
//...
};
T is the type of values stored in these sets. proto should be an instance of T which is used as the "null" value of type T for the purposes of set inclusion. I am reasonably experienced with C++ but not especially with TMP and, although it seems like something which should be embarrassingly simple to pull off, I cannot seem to figure out how something like my pseudo-code "class T inherits Key" is actually done in C++. I want to be able to create a hash-set of instances of C like:
HashSet<C, C::null> myset;
Can somebody please tell me what the proper and idiomatic way to handle this situation in C++ would be? Thank you!
You can use std::enable_if_t
and std::is_base_of
for this:
template<class T, const T& proto,
std::enable_if_t<std::is_base_of<Key,T>::value>* = nullptr>
class HashSet
{
//...
};
Now HashSet
instantiations are only valid if T
inherits from Key
.
std::enable_if_t
is a C++14 feature. You can use typename std::enable_if<...>::type
if you're stuck with C++11.
Live Demo
Another option would be to use static_assert
:
template<class T, const T& proto>
class HashSet
{
static_assert(std::is_base_of<Key, T>::value, "T must inherit from Key");
};
This is maybe a bit clearer and gives you a more friendly error message, but your type constraint is no longer given in the class declaration.
With Concepts we'll get clarity, better error messages and keep our constraints in the declaration:
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
{};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With