From 47df6bd0febce416ffca53993ec89b29a29b3a89 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 8 Feb 2006 19:03:09 +0000 Subject: [PATCH] Update the portable example to hopefully be more generally portable. Change hash_fwd_test to avoid a Borland bug, add 'hash_friend_test' to test for it. Fix a typo in hash_fwd_test. [SVN r32747] --- hash/doc/hash.qbk | 59 ++++++++++++++++++++++++------------- hash/examples/portable.cpp | 38 ++++++++++-------------- hash/test/Jamfile | 1 + hash/test/Jamfile.v2 | 1 + hash/test/hash_fwd_test.hpp | 49 +++++++++++++++--------------- 5 files changed, 82 insertions(+), 66 deletions(-) diff --git a/hash/doc/hash.qbk b/hash/doc/hash.qbk index ba44de2..f88f5fe 100644 --- a/hash/doc/hash.qbk +++ b/hash/doc/hash.qbk @@ -285,11 +285,14 @@ Let's say we have a simple custom type: namespace foo { - struct custom_type + template + class custom_type { - int value; + T value; + public: + custom_type(T x) : value(x) {} - friend inline std::size_t hash_value(custom_type x) + friend std::size_t hash_value(custom_type x) { __boost_hash hasher; return hasher(x.value); @@ -300,34 +303,48 @@ Let's say we have a simple custom type: 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 on these compilers define a member function: +So move the member function out of the class: - #ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP - friend inline std::size_t hash_value(custom_type x) - { - __boost_hash hasher; - return hasher(x.value); - } - #else - std::size_t hash() const - { - __boost_hash hasher; - return hasher(value); - } - #endif + namespace foo + { + template + class custom_type + { + T value; + public: + custom_type(T x) : value(x) {} -which will be called from the `boost` namespace: + template + friend std::size_t hash_value(custom_type x); + }; + + template + friend inline std::size_t hash_value(custom_type x) + { + __boost_hash hasher; + return hasher(x.value); + } + } + +Now compilers which can't find the friend inside the class will find it. +On compilers which don't support ADL, define in the boost namespace: #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP namespace boost + #else + namespace foo + #endif { - std::size_t hash_value(foo::custom_type x) + template + std::size_t hash_value(foo::custom_type x) { - return x.hash(); + boost::hash hasher; + return hasher(x.value); } } - #endif Full code for this example is at [@../../libs/functional/hash/examples/portable.cpp /libs/functional/hash/examples/portable.cpp]. diff --git a/hash/examples/portable.cpp b/hash/examples/portable.cpp index 12d6505..8919c8c 100644 --- a/hash/examples/portable.cpp +++ b/hash/examples/portable.cpp @@ -12,43 +12,37 @@ namespace foo { - struct custom_type + template + class custom_type { - int value; + T value; + public: + custom_type(T x) : value(x) {} - custom_type(int x) : value(x) {} - -#ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP - friend inline std::size_t hash_value(custom_type x) - { - boost::hash hasher; - return hasher(x.value); - } -#else - std::size_t hash() const - { - boost::hash hasher; - return hasher(value); - } -#endif + template + friend std::size_t hash_value(foo::custom_type x); }; } #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP namespace boost +#else +namespace foo +#endif { - std::size_t hash_value(foo::custom_type x) + template + std::size_t hash_value(foo::custom_type x) { - return x.hash(); + boost::hash hasher; + return hasher(x.value); } } -#endif int main() { - foo::custom_type x(1), y(2), z(1); + foo::custom_type x(1), y(2), z(1); - boost::hash hasher; + boost::hash > hasher; assert(hasher(x) == hasher(x)); assert(hasher(x) != hasher(y)); diff --git a/hash/test/Jamfile b/hash/test/Jamfile index dfc797c..f87d49e 100644 --- a/hash/test/Jamfile +++ b/hash/test/Jamfile @@ -33,6 +33,7 @@ rule hash-test ( names + : extras * ) [ hash-test hash_range_test ] [ hash-test hash_custom_test ] [ hash-test hash_global_namespace_test ] + [ hash-test hash_friend_test ] [ hash-test hash_built_in_array_test ] [ hash-test hash_value_array_test ] [ hash-test hash_vector_test ] diff --git a/hash/test/Jamfile.v2 b/hash/test/Jamfile.v2 index 53f915b..b1c714b 100644 --- a/hash/test/Jamfile.v2 +++ b/hash/test/Jamfile.v2 @@ -25,6 +25,7 @@ test-suite functional/hash [ run hash_range_test.cpp framework ] [ run hash_custom_test.cpp framework ] [ run hash_global_namespace_test.cpp framework ] + [ run hash_friend_test.cpp framework ] [ run hash_built_in_array_test.cpp framework ] [ run hash_value_array_test.cpp framework ] [ run hash_vector_test.cpp framework ] diff --git a/hash/test/hash_fwd_test.hpp b/hash/test/hash_fwd_test.hpp index 18e1d2e..5532a62 100644 --- a/hash/test/hash_fwd_test.hpp +++ b/hash/test/hash_fwd_test.hpp @@ -14,29 +14,32 @@ namespace test { -template -struct test_type1 -{ - T value; - test_type1(T const& x) : value(x) {} + template + struct test_type1 + { + T value; + test_type1(T const& x) : value(x) {} + }; #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) - friend std::size_t hash_value(test_type1 const& x) + template + std::size_t hash_value(test_type1 const& x) { HASH_NAMESPACE::hash hasher; return hasher(x.value); } #endif -}; -template -struct test_type2 -{ - T value1, value2; - test_type2(T const& x, T const& y) : value1(x), value2(y) {} + template + struct test_type2 + { + T value1, value2; + test_type2(T const& x, T const& y) : value1(x), value2(y) {} + }; #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) - friend std::size_t hash_value(test_type2 const& x) + template + std::size_t hash_value(test_type2 const& x) { std::size_t seed = 0; HASH_NAMESPACE::hash_combine(seed, x.value1); @@ -44,28 +47,28 @@ struct test_type2 return seed; } #endif -}; -template -struct test_type3 -{ - std::vector values; - test_type3(typename std::vector::iterator x, - typename std::vector::iterator y) : values(x, y) {} + template + struct test_type3 + { + std::vector values; + test_type3(typename std::vector::iterator x, + typename std::vector::iterator y) : values(x, y) {} + }; #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) - friend std::size_t hash_value(test_type3 const& x) + template + std::size_t hash_value(test_type3 const& x) { std::size_t seed = HASH_NAMESPACE::hash_range(x.values.begin(), x.values.end()); HASH_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end()); return seed; } #endif -}; } -#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOPUP) +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) namespace boost {