mirror of
https://github.com/boostorg/functional.git
synced 2025-08-02 22:14:28 +02:00
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:
@@ -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)
|
|
||||||
{
|
{
|
||||||
__boost_hash<int> hasher;
|
template <class T>
|
||||||
|
class custom_type
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
public:
|
||||||
|
custom_type(T x) : value(x) {}
|
||||||
|
|
||||||
|
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);
|
return hasher(x.value);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
std::size_t hash() const
|
|
||||||
{
|
|
||||||
__boost_hash<int> hasher;
|
|
||||||
return hasher(value);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
which will be called from the `boost` namespace:
|
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
|
||||||
std::size_t hash_value(foo::custom_type x)
|
namespace foo
|
||||||
{
|
|
||||||
return x.hash();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
std::size_t hash_value(foo::custom_type<T> x)
|
||||||
|
{
|
||||||
|
boost::hash<T> hasher;
|
||||||
|
return hasher(x.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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].
|
||||||
|
@@ -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));
|
||||||
|
@@ -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 ]
|
||||||
|
@@ -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 ]
|
||||||
|
@@ -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
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user