To narrow it down: I'm currently using Boost.Unordered. I see two possible solutions:
Define my own Equality Predicates and Hash Functions and to utilize templates (maybe
is_pointer
) to distinct between pointers and instances;Simply to extend
boost::hash
by providinghash_value(Type* const& x)
as for hashing; and add==
operator overload as free function with(Type* const& x, Type* const& y)
parameters as for equality checking.
I'm not sure whether both variations are actually possible, since I didn't test them. I would like to find out you handle this problem. Implementations are welcome :)
EDIT 1: What about this?
template<class T>
struct Equals: std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
return left == right;
}
};
template<class T>
struct Equals<T*> : std::binary_function<T*, T*, bool> {
bool operator()(T* const& left, T* const& right) const {
return *left == *right;
}
};
EDIT 2:
I've just defined:
friend std::size_t hash_value(Base const& base) {
boost::hash<std::string> hash;
return hash(base.string_);
}
friend std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
And then:
Derived d1("x");
Derived d2("x");
unordered_set<Base*> set;
set.insert(&d1);
assert(set.find(&d2) == end());
Debugger says that friend std::size_t hash_value(Base* const& base)
is never called (GCC 4.7). Why is that?
EDIT 3:
I found out that template <class T> std::size_t hash_value(T* const& v)
in boost/functional/hash.hpp
on line #215 (Boost 1.49) is Boost's specialization for pointers and it simply masks your custom implementation of hash_value
such as mine in EDIT 2.
Therefore, it seems like the only way here is to create a custom Hash Functor.
Taking into consideration all edits in the original post I would like to provide complete solution which satisfies my needs:
1. Equality:
2. Hashing:
So now I can continue using Boost's
hash_value
and it will not get masked for pointer types by Boost's default implementation (see EDIT 3).3. Example:
In my application I have a thin wrapper for
unordered_set
which now looks like that:So if we have some base class:
And some derived class:
Then we can even use polymorphism (which was my primary intention BTW):
Hope this helps. Any suggestions are welcome.
For the hash function, you have a choice between specializing
boost::hash
(orstd::hash
in the newer standard) or defining a new functor class. These alternatives work equally well.For the equality operator, you need to define a new functor, because you cannot redefine the equality operator over pointers. It's a built-in operator (defined in functional terms as
bool operator==( T const *x, T const *y )
) and cannot be replaced.Both of these can be defined generically by using a templated
operator()
in a non-templated class.Follow a similar pattern for the hasher.