1 2[/ Copyright 2005-2008 Daniel James. 3 / Distributed under the Boost Software License, Version 1.0. (See accompanying 4 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] 5 6[section:portability Portability] 7 8[def __boost_hash__ [classref boost::hash]] 9 10__boost_hash__ is written to be as portable as possible, but unfortunately, several 11older compilers don't support argument dependent lookup (ADL) - the mechanism 12used for customisation. On those compilers custom overloads for `hash_value` 13needs to be declared in the boost namespace. 14 15On a strictly standards compliant compiler, an overload defined in the 16boost namespace won't be found when __boost_hash__ is instantiated, 17so for these compilers the overload should only be declared in the same 18namespace as the class. 19 20Let's say we have a simple custom type: 21 22 namespace foo 23 { 24 template <class T> 25 class custom_type 26 { 27 T value; 28 public: 29 custom_type(T x) : value(x) {} 30 31 friend std::size_t hash_value(custom_type x) 32 { 33 __boost_hash__<int> hasher; 34 return hasher(x.value); 35 } 36 }; 37 } 38 39On a compliant compiler, when `hash_value` is called for this type, 40it will look at the namespace inside the type and find `hash_value` 41but on a compiler which doesn't support ADL `hash_value` won't be found. 42To make things worse, some compilers which do support ADL won't find 43a friend class defined inside the class. 44 45So first move the member function out of the class: 46 47 namespace foo 48 { 49 template <class T> 50 class custom_type 51 { 52 T value; 53 public: 54 custom_type(T x) : value(x) {} 55 56 std::size_t hash(custom_type x) 57 { 58 __boost_hash__<T> hasher; 59 return hasher(value); 60 } 61 }; 62 63 template <class T> 64 inline std::size_t hash_value(custom_type<T> x) 65 { 66 return x.hash(); 67 } 68 } 69 70Unfortunately, I couldn't declare hash_value as a friend, as some compilers 71don't support template friends, so instead I declared a member function to 72calculate the hash, and called it from hash_value. 73 74For compilers which don't support ADL, hash_value needs to be defined in the 75boost namespace: 76 77 #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP 78 namespace boost 79 #else 80 namespace foo 81 #endif 82 { 83 template <class T> 84 std::size_t hash_value(foo::custom_type<T> x) 85 { 86 return x.hash(); 87 } 88 } 89 90Full code for this example is at 91[@boost:/libs/container_hash/examples/portable.cpp /libs/container_hash/examples/portable.cpp]. 92 93[endsect] 94