diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index de942c37..f352ba5b 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -517,44 +517,137 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////////// // Node Constructors + template + struct emulated_pair_constructor + { + enum { value = false }; + }; + + template + struct emulated_pair_constructor, void> + { + enum { value = true }; + }; + + template + struct emulated_pair_constructor, Value> + { + static choice1::type check(choice1, std::pair const&); + static choice2::type check(choice2, A const&); + + enum { value = sizeof(check(choose(), make())) - 1 }; + }; + + template + inline void construct_impl(void* address) + { + new(address) T(); + } + #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - template - inline void construct_impl(T*, void* address, Args&&... args) + template + inline void construct_impl( + typename boost::disable_if, + void*>::type address, + Arg1&& a1) { - new(address) T(std::forward(args)...); + new(address) T(boost::forward(a1)); + } + + template + inline void construct_impl( + typename boost::enable_if, + void*>::type address, + Arg1&& a1) + { + new(address) T(boost::forward(a1), typename T::second_type()); + } + + template + inline void construct_impl(void* address, Arg1&& a1, Arg2&& a2) + { + new(address) T(std::forward(a1, a2)); + } + + template + inline typename boost::disable_if, void>::type + construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Args&&... args) + { + new(address) T(std::forward(arg1, arg2, args)...); + } + + template + inline typename boost::enable_if, void>::type + construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Args&&... args) + { + new(address) T(std::forward(arg1), + typename T::second_type(std::forward(arg2, args)...)); } #else -#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ - template < \ - class T, \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ - > \ - inline void construct_impl( \ - T*, void* address, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ - ) \ - { \ - new(address) T( \ - BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ - } \ - \ - template \ - inline void construct_impl( \ - std::pair*, void* address, \ - Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ - { \ - new(address) std::pair(k, \ - Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \ + template + inline BOOST_DEDUCED_TYPENAME boost::disable_if, void>::type + construct_impl(void* address, BOOST_FWD_REF(Arg1) a1) + { + new(address) T(boost::forward(a1)); } - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, + template + inline BOOST_DEDUCED_TYPENAME boost::enable_if, void>::type + construct_impl(void* address, BOOST_FWD_REF(Arg1) a1) + { + new(address) T( + boost::forward(a1), + BOOST_DEDUCED_TYPENAME T::second_type() + ); + } + + template + inline void construct_impl(void* address, + BOOST_FWD_REF(Arg1) a1, BOOST_FWD_REF(Arg2) a2) + { + new(address) T(boost::forward(a1), boost::forward(a2)); + } + +#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ + template < \ + class T, \ + BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ + > \ + inline void construct_impl( \ + BOOST_DEDUCED_TYPENAME \ + boost::disable_if, void*>::type \ + address, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ + ) \ + { \ + new(address) T( \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ + } + + BOOST_PP_REPEAT_FROM_TO(3, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_CONSTRUCT_IMPL, _) +#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \ + template \ + inline void construct_impl( \ + BOOST_DEDUCED_TYPENAME \ + boost::enable_if, void*>::type \ + address, \ + Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + { \ + new(address) T(k, \ + BOOST_DEDUCED_TYPENAME \ + T::second_type(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \ + } + + BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _) + #undef BOOST_UNORDERED_CONSTRUCT_IMPL #endif @@ -594,7 +687,7 @@ namespace boost { namespace unordered { namespace detail { void construct(Args&&... args) { construct_preamble(); - construct_impl((value_type*) 0, node_->address(), + construct_impl(node_->address(), std::forward(args)...); value_constructed_ = true; } @@ -609,8 +702,7 @@ namespace boost { namespace unordered { namespace detail { ) \ { \ construct_preamble(); \ - construct_impl( \ - (value_type*) 0, node_->address(), \ + construct_impl(node_->address(), \ BOOST_UNORDERED_CALL_PARAMS(z, num_params) \ ); \ value_constructed_ = true; \ diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 8abc63b9..8f8c58a9 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -514,6 +514,46 @@ UNORDERED_AUTO_TEST(insert_initializer_list_multimap) #endif +struct overloaded_constructor +{ + overloaded_constructor(int x = 1, int y = 2, int z = 3) + : x(x), y(y), z(z) {} + + int x, y, z; + + bool operator==(overloaded_constructor const& rhs) const + { + return x == rhs.x && y == rhs.y && z == rhs.z; + } +}; + +// This will actually be deprecated pretty soon. + +UNORDERED_AUTO_TEST(map_emplace_test) +{ + boost::unordered_map x; + + x.emplace(); + BOOST_TEST(x.find(0) != x.end() && + x.find(0)->second == overloaded_constructor()); + + x.emplace(1); + BOOST_TEST(x.find(1) != x.end() && + x.find(1)->second == overloaded_constructor()); + + x.emplace(2, 3); + BOOST_TEST(x.find(2) != x.end() && + x.find(2)->second == overloaded_constructor(3)); + + x.emplace(4, 5, 6); + BOOST_TEST(x.find(4) != x.end() && + x.find(4)->second == overloaded_constructor(5, 6)); + + x.emplace(7, 8, 9, 10); + BOOST_TEST(x.find(7) != x.end() && + x.find(7)->second == overloaded_constructor(8, 9, 10)); +} + } RUN_TESTS()