portability.qbk 2.7 KB

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