94 lines
2.7 KiB
Plaintext
94 lines
2.7 KiB
Plaintext
|
|
[/ Copyright 2005-2008 Daniel James.
|
|
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
|
|
|
[section:portability Portability]
|
|
|
|
[def __boost_hash__ [classref boost::hash]]
|
|
|
|
__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
|
|
[@boost:/libs/container_hash/examples/portable.cpp /libs/container_hash/examples/portable.cpp].
|
|
|
|
[endsect]
|