Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Portability

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/functional/hash/examples/portable.cpp.


PrevUpHomeNext