Unordered: New member function detection.

Based on Ion's `has_member_function_callable_with`.

[SVN r74532]
This commit is contained in:
Daniel James
2011-09-22 23:56:49 +00:00
parent 78241de393
commit 340c98d89a
2 changed files with 114 additions and 58 deletions

View File

@ -19,8 +19,10 @@
#include <boost/detail/select_type.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/enum.hpp>
#include <boost/limits.hpp>
#include <boost/type_traits/add_lvalue_reference.hpp>
#include <boost/pointer_to_other.hpp>
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
# include <memory>
@ -97,6 +99,22 @@ namespace boost { namespace unordered { namespace detail {
struct choice1 : choice2 { typedef char (&type)[1]; };
choice1 choose();
typedef choice1::type yes_type;
typedef choice2::type no_type;
struct private_type
{
private_type const &operator,(int) const;
};
template <typename T>
no_type is_private_type(T const&);
yes_type is_private_type(private_type const&);
struct convert_from_anything {
convert_from_anything(...);
};
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
@ -176,44 +194,40 @@ namespace boost { namespace unordered { namespace detail {
static BOOST_PP_CAT(choice, result)::type test( \
BOOST_PP_CAT(choice, count))
#define BOOST_UNORDERED_HAS_EXPRESSION(name, expression) \
#define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \
struct BOOST_PP_CAT(has_, name) \
{ \
BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, expression); \
BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, make< thing >().name args); \
BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \
\
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };\
}
template <typename T>
BOOST_UNORDERED_HAS_EXPRESSION(
select_on_container_copy_construction,
make<U const>().select_on_container_copy_construction()
BOOST_UNORDERED_HAS_FUNCTION(
select_on_container_copy_construction, U const, (), 0
);
// Only supporting the basic copy constructor for now.
template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_EXPRESSION(
construct,
make<U>().construct(make<ValueType*>(), make<ValueType const>())
BOOST_UNORDERED_HAS_FUNCTION(
construct, U, (make<ValueType*>(), make<ValueType const>()), 2
);
template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_EXPRESSION(
destroy,
make<U>().destroy(make<ValueType*>())
BOOST_UNORDERED_HAS_FUNCTION(
destroy, U, (make<ValueType*>()), 1
);
template <typename T>
BOOST_UNORDERED_HAS_EXPRESSION(
max_size,
make<U const>().max_size()
BOOST_UNORDERED_HAS_FUNCTION(
max_size, U const, (), 0
);
#else
template <typename T> struct identity { typedef T type; };
template <typename T> struct identity { typedef T type; };
#define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \
\
@ -232,27 +246,73 @@ namespace boost { namespace unordered { namespace detail {
template <class U> static BOOST_PP_CAT(choice, result)::type \
test(BOOST_PP_CAT(choice, count))
#define BOOST_UNORDERED_WRAP_PARAMATERS(z, n, data) convert_from_anything
#define BOOST_UNORDERED_HAS_MEMBER(name) \
struct BOOST_PP_CAT(has_, name) \
{ \
struct base_mixin { void name(); }; \
struct base : public T, public base_mixin {}; \
\
BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, void (base_mixin::*)()); \
BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \
\
enum { value = sizeof(choice2::type) == \
sizeof(test<base>(choose())) \
}; \
}
#define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, arg_count) \
struct BOOST_PP_CAT(has_, name) \
{ \
struct base_mixin { void name(); }; \
struct base : public T, public base_mixin {}; \
\
BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, void (base_mixin::*)()); \
BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \
\
enum { has_member = sizeof(choice2::type) == \
sizeof(test<base>(choose())) \
}; \
\
template <typename U> \
struct wrap : U \
{ \
using U::name; \
private_type name( \
BOOST_PP_ENUM(arg_count, BOOST_UNORDERED_WRAP_PARAMATERS, _) \
); \
}; \
\
template <typename U> \
struct impl \
{ \
enum { value = sizeof(is_private_type(( \
make<wrap< thing > >().name args \
, 0))) == sizeof(yes_type) }; \
}; \
\
enum { value = \
boost::detail::if_true<has_member>:: \
BOOST_NESTED_TEMPLATE then<impl<T>, false_type>::type::value \
}; \
}
template <typename T>
struct has_select_on_container_copy_construction
{
BOOST_UNORDERED_CHECK_MEMBER(1, 1,
select_on_container_copy_construction,
T (T::*)() const);
BOOST_UNORDERED_DEFAULT_MEMBER(2, 2);
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };
};
BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction);
// Detection isn't reliable enough, so just assume that we have these
// functions.
template <typename Alloc, typename value_type>
struct has_construct : true_type {};
template <typename Alloc, typename value_type>
struct has_destroy : true_type {};
template <typename Alloc>
struct has_max_size : true_type {};
template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_FUNCTION(
construct, U, (make<ValueType*>(), make<ValueType const>()), 2
);
template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_FUNCTION(
destroy, U, (make<ValueType*>()), 1
);
template <typename T>
BOOST_UNORDERED_HAS_MEMBER(max_size);
#endif
@ -295,27 +355,20 @@ namespace boost { namespace unordered { namespace detail {
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*)
pointer;
// For now always use the allocator's const_pointer.
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
// typename pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<const value_type>::other)
// const_pointer;
template <typename T>
struct pointer_to_other : boost::pointer_to_other<pointer, T> {};
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
value_type const*) const_pointer;
typename pointer_to_other<const value_type>::type)
const_pointer;
// I'm not using void pointers for now.
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer,
typename pointer_to_other<void>::type)
void_pointer;
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer,
// BOOST_NESTED_TEMPLATE pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<void>::other)
// void_pointer;
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
// typename pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<const void>::other)
// const_void_pointer;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
typename pointer_to_other<const void>::type)
const_void_pointer;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, difference_type,
std::ptrdiff_t) difference_type;

View File

@ -136,8 +136,17 @@ void test_allocator1()
// allocator 2
template <typename Alloc>
struct allocator2_base
{
Alloc select_on_container_copy_construction() const {
++selected;
return Alloc();
}
};
template <typename T>
struct allocator2
struct allocator2 : allocator2_base<allocator2<T> >
{
typedef T value_type;
typedef T* pointer;
@ -149,12 +158,6 @@ struct allocator2
typedef no_type propagate_on_container_copy_assignment;
typedef no_type propagate_on_container_move_assignment;
typedef no_type propagate_on_container_swap;
// Note: Not const - so it shouldn't be called.
allocator2<T> select_on_container_copy_construction() {
++selected;
return allocator2<T>();
}
};
void test_allocator2()
@ -169,7 +172,7 @@ void test_allocator2()
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
BOOST_TEST(!traits::propagate_on_container_swap::value);
BOOST_TEST(call_select<allocator>() == 0);
BOOST_TEST(call_select<allocator>() == 1);
}
// allocator 3