У меня есть класс-оболочка для std::string
, который служит базовым классом для нескольких других.Экземпляры подклассов будут использоваться в качестве ключей в std::unordered_set
, поэтому мне нужно предоставить для них хеш-функцию.Поскольку хеш зависит только от std::string
, хранящегося в базовом классе, я не хочу писать хеш-функцию для каждого подкласса, а вместо этого использую функцию из класса-оболочки.
Вот как я хотел бы решить эту проблему:
#include <string>
#include <unordered_set>
class Wrapper {
public:
std::string name;
size_t _hash;
explicit Wrapper(std::string str) : name(str), _hash(std::hash<std::string>()(name)) {}
size_t hash() const { return _hash; }
};
class Derived : public Wrapper {};
namespace std {
template <> struct hash<Wrapper> {
std::size_t operator()(const Wrapper &k) const { return k.hash(); }
};
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
std::size_t operator()(const T &k) const { return k.hash(); }
};
} // namespace std
int main(void) {
std::unordered_set<Wrapper> m1;
std::unordered_set<Derived> m2;
}
Конечно, это не компилируется, так как T
не может быть выведено.Clang говорит:
20:30: error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
20:20: note: non-deducible template parameter 'T'
А g ++ говорит:
hash_subclass.cpp:21:30: error: template parameters not deducible in partial specialization:
template <typename T> struct hash<std::enable_if_t<std::is_base_of_v<Wrapper, T>>> {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hash_subclass.cpp:21:30: note: 'T'
Я нашел это решение, но я бы хотел избежать использования макроса.Кроме того, это противоречит тому, что я ожидаю от наследования.
Есть ли решение для этого?Может ли подкласс наследовать специализацию своего базового класса std::hash
?
Кроме того, я не уверен на 100% в своем использовании std::enable_if
и std::is_base_of
.Не могли бы вы сказать мне, будет ли это работать, если предположить, что T
может быть выведено?