...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
boost::hash
is written to be as portable
as possible, but unfortunately, several older compilers don't support argument
dependent lookup (ADL) - the mechanism used for customisation. On those compilers
custom overloads for hash_value
needs to be declared in the boost namespace.
On a strictly standards compliant compiler, an overload defined in the boost
namespace won't be found when boost::hash
is instantiated, so for these compilers the overload should only be declared
in the same namespace as the class.
Let's say we have a simple custom type:
namespace foo
{
template <class T>
class custom_type
{
T value;
public:
custom_type(T x) : value(x) {}
friend std::size_t hash_value(custom_type x)
{
boost::hash
<int> hasher;
return hasher(x.value);
}
};
}
On a compliant compiler, when hash_value
is called for this type, it will look at the namespace inside the type and
find hash_value
but on a compiler
which doesn't support ADL hash_value
won't be found. To make things worse, some compilers which do support ADL won't
find a friend class defined inside the class.
So first move the member function out of the class:
namespace foo
{
template <class T>
class custom_type
{
T value;
public:
custom_type(T x) : value(x) {}
std::size_t hash(custom_type x)
{
boost::hash
<T> hasher;
return hasher(value);
}
};
template <class T>
inline std::size_t hash_value(custom_type<T> x)
{
return x.hash();
}
}
Unfortunately, I couldn't declare hash_value as a friend, as some compilers don't support template friends, so instead I declared a member function to calculate the hash, and called it from hash_value.
For compilers which don't support ADL, hash_value needs to be defined in the boost namespace:
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP namespace boost #else namespace foo #endif { template <class T> std::size_t hash_value(foo::custom_type<T> x) { return x.hash(); } }
Full code for this example is at /libs/container_hash/examples/portable.cpp.