forked from boostorg/container_hash
Add Portability section to AsciiDoc
This commit is contained in:
@@ -2,3 +2,81 @@
|
||||
= Portability
|
||||
|
||||
:idprefix: portability_
|
||||
|
||||
xref:#ref_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 xref:#ref_hash[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:
|
||||
|
||||
[list,subs="+quotes,+macros"]
|
||||
----
|
||||
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)
|
||||
{
|
||||
xref:#ref_hash[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:
|
||||
|
||||
[listing,subs="+quotes,+macros"]
|
||||
----
|
||||
namespace foo
|
||||
{
|
||||
template <class T>
|
||||
class custom_type
|
||||
{
|
||||
T value;
|
||||
public:
|
||||
custom_type(T x) : value(x) {}
|
||||
|
||||
std::size_t hash(custom_type x)
|
||||
{
|
||||
xref:#ref_hash[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:
|
||||
|
||||
[listing]
|
||||
----
|
||||
#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 link:../../examples/portable.cpp[/libs/container_hash/examples/portable.cpp^].
|
||||
|
Reference in New Issue
Block a user