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/detail/select_type.hpp>
#include <boost/utility/enable_if.hpp> #include <boost/utility/enable_if.hpp>
#include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/enum.hpp>
#include <boost/limits.hpp> #include <boost/limits.hpp>
#include <boost/type_traits/add_lvalue_reference.hpp> #include <boost/type_traits/add_lvalue_reference.hpp>
#include <boost/pointer_to_other.hpp>
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS #if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
# include <memory> # include <memory>
@ -97,6 +99,22 @@ namespace boost { namespace unordered { namespace detail {
struct choice1 : choice2 { typedef char (&type)[1]; }; struct choice1 : choice2 { typedef char (&type)[1]; };
choice1 choose(); 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 #if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
#define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ #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( \ static BOOST_PP_CAT(choice, result)::type test( \
BOOST_PP_CAT(choice, count)) 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) \ 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); \ BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \
\ \
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };\ enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };\
} }
template <typename T> template <typename T>
BOOST_UNORDERED_HAS_EXPRESSION( BOOST_UNORDERED_HAS_FUNCTION(
select_on_container_copy_construction, select_on_container_copy_construction, U const, (), 0
make<U const>().select_on_container_copy_construction()
); );
// Only supporting the basic copy constructor for now. // Only supporting the basic copy constructor for now.
template <typename T, typename ValueType> template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_EXPRESSION( BOOST_UNORDERED_HAS_FUNCTION(
construct, construct, U, (make<ValueType*>(), make<ValueType const>()), 2
make<U>().construct(make<ValueType*>(), make<ValueType const>())
); );
template <typename T, typename ValueType> template <typename T, typename ValueType>
BOOST_UNORDERED_HAS_EXPRESSION( BOOST_UNORDERED_HAS_FUNCTION(
destroy, destroy, U, (make<ValueType*>()), 1
make<U>().destroy(make<ValueType*>())
); );
template <typename T> template <typename T>
BOOST_UNORDERED_HAS_EXPRESSION( BOOST_UNORDERED_HAS_FUNCTION(
max_size, max_size, U const, (), 0
make<U const>().max_size()
); );
#else #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) \ #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 \ template <class U> static BOOST_PP_CAT(choice, result)::type \
test(BOOST_PP_CAT(choice, count)) 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> template <typename T>
struct has_select_on_container_copy_construction BOOST_UNORDERED_HAS_MEMBER(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) };
};
// Detection isn't reliable enough, so just assume that we have these template <typename T, typename ValueType>
// functions. BOOST_UNORDERED_HAS_FUNCTION(
construct, U, (make<ValueType*>(), make<ValueType const>()), 2
template <typename Alloc, typename value_type> );
struct has_construct : true_type {};
template <typename Alloc, typename value_type> template <typename T, typename ValueType>
struct has_destroy : true_type {}; BOOST_UNORDERED_HAS_FUNCTION(
template <typename Alloc> destroy, U, (make<ValueType*>()), 1
struct has_max_size : true_type {}; );
template <typename T>
BOOST_UNORDERED_HAS_MEMBER(max_size);
#endif #endif
@ -295,27 +355,20 @@ namespace boost { namespace unordered { namespace detail {
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*) typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*)
pointer; pointer;
// For now always use the allocator's const_pointer. template <typename T>
struct pointer_to_other : boost::pointer_to_other<pointer, T> {};
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
// typename pointer_traits<pointer>::
// BOOST_NESTED_TEMPLATE rebind<const value_type>::other)
// const_pointer;
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, 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, typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
// BOOST_NESTED_TEMPLATE pointer_traits<pointer>:: typename pointer_to_other<const void>::type)
// BOOST_NESTED_TEMPLATE rebind<void>::other) const_void_pointer;
// 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, difference_type, typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, difference_type,
std::ptrdiff_t) difference_type; std::ptrdiff_t) difference_type;

View File

@ -136,8 +136,17 @@ void test_allocator1()
// allocator 2 // allocator 2
template <typename Alloc>
struct allocator2_base
{
Alloc select_on_container_copy_construction() const {
++selected;
return Alloc();
}
};
template <typename T> template <typename T>
struct allocator2 struct allocator2 : allocator2_base<allocator2<T> >
{ {
typedef T value_type; typedef T value_type;
typedef T* pointer; typedef T* pointer;
@ -149,12 +158,6 @@ struct allocator2
typedef no_type propagate_on_container_copy_assignment; typedef no_type propagate_on_container_copy_assignment;
typedef no_type propagate_on_container_move_assignment; typedef no_type propagate_on_container_move_assignment;
typedef no_type propagate_on_container_swap; 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() 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_copy_assignment::value);
BOOST_TEST(!traits::propagate_on_container_move_assignment::value); BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
BOOST_TEST(!traits::propagate_on_container_swap::value); BOOST_TEST(!traits::propagate_on_container_swap::value);
BOOST_TEST(call_select<allocator>() == 0); BOOST_TEST(call_select<allocator>() == 1);
} }
// allocator 3 // allocator 3