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]
This commit is contained in:
Daniel James
2006-02-08 19:03:09 +00:00
parent bb702b827e
commit 47df6bd0fe
5 changed files with 82 additions and 66 deletions

View File

@@ -285,11 +285,14 @@ Let's say we have a simple custom type:
namespace foo namespace foo
{ {
struct custom_type template <class T>
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<int> hasher; __boost_hash<int> hasher;
return hasher(x.value); 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, 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` 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. 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 namespace foo
friend inline std::size_t hash_value(custom_type x) {
{ template <class T>
__boost_hash<int> hasher; class custom_type
return hasher(x.value); {
} T value;
#else public:
std::size_t hash() const custom_type(T x) : value(x) {}
{
__boost_hash<int> hasher;
return hasher(value);
}
#endif
which will be called from the `boost` namespace: template <class T2>
friend std::size_t hash_value(custom_type<T2> x);
};
template <class T>
friend inline std::size_t hash_value(custom_type<T> x)
{
__boost_hash<T> 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 #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
namespace boost namespace boost
#else
namespace foo
#endif
{ {
std::size_t hash_value(foo::custom_type x) template <class T>
std::size_t hash_value(foo::custom_type<T> x)
{ {
return x.hash(); boost::hash<T> hasher;
return hasher(x.value);
} }
} }
#endif
Full code for this example is at Full code for this example is at
[@../../libs/functional/hash/examples/portable.cpp /libs/functional/hash/examples/portable.cpp]. [@../../libs/functional/hash/examples/portable.cpp /libs/functional/hash/examples/portable.cpp].

View File

@@ -12,43 +12,37 @@
namespace foo namespace foo
{ {
struct custom_type template <class T>
class custom_type
{ {
int value; T value;
public:
custom_type(T x) : value(x) {}
custom_type(int x) : value(x) {} template <class T2>
friend std::size_t hash_value(foo::custom_type<T2> x);
#ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
friend inline std::size_t hash_value(custom_type x)
{
boost::hash<int> hasher;
return hasher(x.value);
}
#else
std::size_t hash() const
{
boost::hash<int> hasher;
return hasher(value);
}
#endif
}; };
} }
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
namespace boost namespace boost
#else
namespace foo
#endif
{ {
std::size_t hash_value(foo::custom_type x) template <class T>
std::size_t hash_value(foo::custom_type<T> x)
{ {
return x.hash(); boost::hash<T> hasher;
return hasher(x.value);
} }
} }
#endif
int main() int main()
{ {
foo::custom_type x(1), y(2), z(1); foo::custom_type<int> x(1), y(2), z(1);
boost::hash<foo::custom_type> hasher; boost::hash<foo::custom_type<int> > hasher;
assert(hasher(x) == hasher(x)); assert(hasher(x) == hasher(x));
assert(hasher(x) != hasher(y)); assert(hasher(x) != hasher(y));

View File

@@ -33,6 +33,7 @@ rule hash-test ( names + : extras * )
[ hash-test hash_range_test ] [ hash-test hash_range_test ]
[ hash-test hash_custom_test ] [ hash-test hash_custom_test ]
[ hash-test hash_global_namespace_test ] [ hash-test hash_global_namespace_test ]
[ hash-test hash_friend_test ]
[ hash-test hash_built_in_array_test ] [ hash-test hash_built_in_array_test ]
[ hash-test hash_value_array_test ] [ hash-test hash_value_array_test ]
[ hash-test hash_vector_test ] [ hash-test hash_vector_test ]

View File

@@ -25,6 +25,7 @@ test-suite functional/hash
[ run hash_range_test.cpp framework ] [ run hash_range_test.cpp framework ]
[ run hash_custom_test.cpp framework ] [ run hash_custom_test.cpp framework ]
[ run hash_global_namespace_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_built_in_array_test.cpp framework ]
[ run hash_value_array_test.cpp framework ] [ run hash_value_array_test.cpp framework ]
[ run hash_vector_test.cpp framework ] [ run hash_vector_test.cpp framework ]

View File

@@ -14,29 +14,32 @@
namespace test { namespace test {
template <class T> template <class T>
struct test_type1 struct test_type1
{ {
T value; T value;
test_type1(T const& x) : value(x) {} test_type1(T const& x) : value(x) {}
};
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
friend std::size_t hash_value(test_type1<T> const& x) template <class T>
std::size_t hash_value(test_type1<T> const& x)
{ {
HASH_NAMESPACE::hash<T> hasher; HASH_NAMESPACE::hash<T> hasher;
return hasher(x.value); return hasher(x.value);
} }
#endif #endif
};
template <class T> template <class T>
struct test_type2 struct test_type2
{ {
T value1, value2; T value1, value2;
test_type2(T const& x, T const& y) : value1(x), value2(y) {} test_type2(T const& x, T const& y) : value1(x), value2(y) {}
};
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
friend std::size_t hash_value(test_type2<T> const& x) template <class T>
std::size_t hash_value(test_type2<T> const& x)
{ {
std::size_t seed = 0; std::size_t seed = 0;
HASH_NAMESPACE::hash_combine(seed, x.value1); HASH_NAMESPACE::hash_combine(seed, x.value1);
@@ -44,28 +47,28 @@ struct test_type2
return seed; return seed;
} }
#endif #endif
};
template <class T> template <class T>
struct test_type3 struct test_type3
{ {
std::vector<T> values; std::vector<T> values;
test_type3(typename std::vector<T>::iterator x, test_type3(typename std::vector<T>::iterator x,
typename std::vector<T>::iterator y) : values(x, y) {} typename std::vector<T>::iterator y) : values(x, y) {}
};
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
friend std::size_t hash_value(test_type3<T> const& x) template <class T>
std::size_t hash_value(test_type3<T> const& x)
{ {
std::size_t seed = HASH_NAMESPACE::hash_range(x.values.begin(), x.values.end()); 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()); HASH_NAMESPACE::hash_range(seed, x.values.begin(), x.values.end());
return seed; return seed;
} }
#endif #endif
};
} }
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOPUP) #if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
namespace boost namespace boost
{ {