diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index 79f40467..c3c080b2 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -5,8 +5,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -// Written by Daniel James using some code from Pablo Halpern's -// allocator traits implementation. +// Allocator traits written by Daniel James based on Pablo Halpern's +// implementation. #ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED @@ -18,6 +18,7 @@ #include #include #include +#include #if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \ && !defined(__BORLANDC__) @@ -81,38 +82,39 @@ namespace boost { namespace unordered { namespace detail { }; # endif - struct convertible_from_anything - { - template convertible_from_anything(T const&); - }; + template T& make(); + struct choice9 { typedef char (&type)[9]; }; + struct choice8 : choice9 { typedef char (&type)[8]; }; + struct choice7 : choice8 { typedef char (&type)[7]; }; + struct choice6 : choice7 { typedef char (&type)[6]; }; + struct choice5 : choice6 { typedef char (&type)[5]; }; + struct choice4 : choice5 { typedef char (&type)[4]; }; + struct choice3 : choice4 { typedef char (&type)[3]; }; + struct choice2 : choice3 { typedef char (&type)[2]; }; + struct choice1 : choice2 { typedef char (&type)[1]; }; + choice1 choose(); - typedef char (&no_type)[1]; - typedef char (&yes_type)[2]; - - template struct sfinae { - typedef yes_type type; - }; - - // Infrastructure for providing a default type for Tp::tname if absent. #define BOOST_DEFAULT_TYPE_TMPLT(tname) \ template \ struct default_type_ ## tname { \ - template \ - static BOOST_DEDUCED_TYPENAME sfinae< \ - BOOST_DEDUCED_TYPENAME T::tname>::type test(int); \ - template \ - static no_type test(long); \ \ - enum { value = sizeof(test(0)) == sizeof(yes_type) }; \ + template \ + static choice1::type test(choice1, \ + BOOST_DEDUCED_TYPENAME X::tname* = 0); \ + \ + template \ + static choice2::type test(choice2, void* = 0); \ \ struct DefaultWrap { typedef Default tname; }; \ \ + enum { value = (1 == sizeof(test(choose()))) }; \ + \ typedef BOOST_DEDUCED_TYPENAME \ boost::detail::if_true:: \ BOOST_NESTED_TEMPLATE then \ ::type::tname type; \ } - + #define BOOST_DEFAULT_TYPE(T,tname, arg) \ BOOST_DEDUCED_TYPENAME default_type_ ## tname::type @@ -127,47 +129,62 @@ namespace boost { namespace unordered { namespace detail { BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_swap); #if !defined(BOOST_NO_SFINAE_EXPR) || BOOST_WORKAROUND(BOOST_MSVC, >= 1500) - // Specialization is only needed for Visual C++. Without it SFINAE doesn't - // kick in. - template - struct expr_sfinae; - - template <> - struct expr_sfinae { - typedef yes_type type; - }; - + + template struct expr_test; + template struct expr_test : T {}; + template static char for_expr_test(U const&); + +#define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \ + template \ + static typename expr_test< \ + BOOST_PP_CAT(choice, result), \ + sizeof(for_expr_test(((expression), 0)))>::type test( \ + BOOST_PP_CAT(choice, count)) + +#define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \ + template \ + static BOOST_PP_CAT(choice, result)::type test( \ + BOOST_PP_CAT(choice, count)) + template struct has_select_on_container_copy_construction { - // This needs to be a template for Visual C++. - template - static yes_type to_yes_type(const T2&); - - template - static typename expr_sfinaeselect_on_container_copy_construction() - ))>::type check(T2*); - - static no_type check(void*); + BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, make().select_on_container_copy_construction()); + BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); - enum { value = sizeof(check((T*) 0)) == sizeof(yes_type) }; + enum { value = sizeof(test(choose())) == sizeof(choice1::type) }; }; + #else + + template struct identity { typedef T type; }; + +#define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \ + \ + typedef typename identity::type BOOST_PP_CAT(check, count); \ + \ + template \ + struct BOOST_PP_CAT(test, count) { \ + typedef void* type; \ + }; \ + \ + template static BOOST_PP_CAT(choice, result)::type \ + test(BOOST_PP_CAT(choice, count), \ + typename BOOST_PP_CAT(test, count)< \ + &U::name>::type = 0) + +#define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ + template static BOOST_PP_CAT(choice, result)::type \ + test(BOOST_PP_CAT(choice, count), void* = 0) + + template struct has_select_on_container_copy_construction { - typedef T (T::*SelectFunc)() const; - - template struct sfinae { typedef yes_type type; }; - - template - static typename sfinae<&U::select_on_container_copy_construction>::type - test(int); - template - static no_type test(...); + BOOST_UNORDERED_CHECK_MEMBER(1, 1, select_on_container_copy_construction, T (T::*)() const); + BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); - enum { value = sizeof(test(1)) == sizeof(yes_type) }; + enum { value = sizeof(test(choose())) == sizeof(choice1::type) }; }; #endif diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index de942c37..4fb1f503 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -517,44 +517,139 @@ 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(std::forward(a1)); + } + + template + inline void construct_impl( + typename boost::enable_if, + void*>::type address, + Arg1&& a1) + { + new(address) T(std::forward(a1), typename T::second_type()); + } + + template + inline void construct_impl(void* address, Arg1&& a1, Arg2&& a2) + { + new(address) T(std::forward(a1), std::forward(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), std::forward(arg2), + std::forward(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), std::forward(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 +689,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 +704,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/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 91c0a098..7f3fa6bb 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -167,7 +167,9 @@ namespace boost { namespace unordered { namespace detail { // // Or from rehash post-condition: // count > size / mlf_ - return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); + return next_prime(double_to_size_t(floor( + static_cast(size) / + static_cast(mlf_))) + 1); } //////////////////////////////////////////////////////////////////////// @@ -451,7 +453,9 @@ namespace boost { namespace unordered { namespace detail { else { // no throw: min_buckets = next_prime((std::max)(min_buckets, - double_to_size_t(floor(this->size_ / (double) mlf_)) + 1)); + double_to_size_t(floor( + static_cast(this->size_) / + static_cast(mlf_))) + 1)); if(min_buckets != this->bucket_count_) { this->rehash_impl(min_buckets); this->max_load_ = calculate_max_load(); diff --git a/test/helpers/memory.hpp b/test/helpers/memory.hpp index 102fd16e..af75328a 100644 --- a/test/helpers/memory.hpp +++ b/test/helpers/memory.hpp @@ -194,8 +194,13 @@ namespace test enum { value = false }; }; - template - int selected_count(Alloc const&) + struct convert_from_anything + { + template + convert_from_anything(T const&) {} + }; + + int selected_count(convert_from_anything) { return 0; } diff --git a/test/objects/cxx11_allocator.hpp b/test/objects/cxx11_allocator.hpp index f909b663..bb51713a 100644 --- a/test/objects/cxx11_allocator.hpp +++ b/test/objects/cxx11_allocator.hpp @@ -186,9 +186,14 @@ namespace test }; template - struct cxx11_allocator : - public cxx11_allocator_base, + typename Enable = void> + struct cxx11_allocator; + + template + struct cxx11_allocator< + T, Flags, + typename boost::disable_if_c::type + > : public cxx11_allocator_base, public swap_allocator_base, public assign_allocator_base, public move_allocator_base, @@ -228,8 +233,10 @@ namespace test }; template - struct cxx11_allocator : - public cxx11_allocator_base, + struct cxx11_allocator< + T, Flags, + typename boost::enable_if_c::type + > : public cxx11_allocator_base, public swap_allocator_base, public assign_allocator_base, public move_allocator_base, diff --git a/test/objects/test.hpp b/test/objects/test.hpp index d1fe5c3b..fc690c13 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -26,7 +26,7 @@ namespace test object generate(object const*); implicitly_convertible generate(implicitly_convertible const*); - class object : globally_counted_object + class object : private globally_counted_object { friend class hash; friend class equal_to; @@ -64,7 +64,7 @@ namespace test } }; - class implicitly_convertible : globally_counted_object + class implicitly_convertible : private globally_counted_object { int tag1_, tag2_; public: diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 8c3fbbcf..9919f61f 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -22,6 +22,7 @@ test-suite unordered : [ run fwd_set_test.cpp ] [ run fwd_map_test.cpp ] + [ run allocator_traits.cpp ] [ run compile_set.cpp ] [ run compile_map.cpp ] [ run link_test_1.cpp link_test_2.cpp ] diff --git a/test/unordered/allocator_traits.cpp b/test/unordered/allocator_traits.cpp new file mode 100644 index 00000000..c27176c4 --- /dev/null +++ b/test/unordered/allocator_traits.cpp @@ -0,0 +1,227 @@ + +// Copyright 2011 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +// Boilerplate + +#define ALLOCATOR_METHODS(name) \ + template struct rebind { \ + typedef name other; \ + }; \ + \ + name() {} \ + template name(name const&) {} \ + T* address(T& r) { return &r;} \ + T const* address(T const& r) { return &r; } \ + T* allocate(std::size_t n) \ + { return static_cast(::operator new(n * sizeof(T))); } \ + T* allocate(std::size_t n, void const* u) \ + { return static_cast(::operator new(n * sizeof(T))); } \ + void deallocate(T* p, std::size_t n) { ::operator delete((void*) p); } \ + void construct(T* p, T const& t) { new(p) T(t); } \ + void destroy(T* p) { p->~T(); } \ + std::size_t max_size() const \ + { return (std::numeric_limits::max)(); } \ + bool operator==(name const&) { return true; } \ + bool operator!=(name const&) { return false; } \ +/**/ + +#define ALLOCATOR_METHODS_TYPEDEFS(name) \ + template struct rebind { \ + typedef name other; \ + }; \ + \ + name() {} \ + template name(name const&) {} \ + pointer address(T& r) { return &r;} \ + const_pointer address(T const& r) { return &r; } \ + pointer allocate(std::size_t n) \ + { return pointer(::operator new(n * sizeof(T))); } \ + pointer allocate(std::size_t n, void const* u) \ + { return pointer(::operator new(n * sizeof(T))); } \ + void deallocate(pointer p, std::size_t n) \ + { ::operator delete((void*) p); } \ + void construct(T* p, T const& t) { new(p) T(t); } \ + void destroy(T* p) { p->~T(); } \ + size_type max_size() const \ + { return (std::numeric_limits::max)(); } \ + bool operator==(name const&) { return true; } \ + bool operator!=(name const&) { return false; } \ +/**/ + +struct yes_type { enum { value = true }; }; +struct no_type { enum { value = false }; }; + +// For tracking calls... + +static int selected; +void reset() { + selected = 0; +} + +template +int call_select() +{ + typedef boost::unordered::detail::allocator_traits traits; + Allocator a; + + reset(); + BOOST_TEST(traits::select_on_container_copy_construction(a) == a); + return selected; +} + +// Empty allocator test + +template +struct empty_allocator +{ + typedef T value_type; + ALLOCATOR_METHODS(empty_allocator) +}; + +void test_empty_allocator() +{ + typedef empty_allocator allocator; + typedef boost::unordered::detail::allocator_traits traits; + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + 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() == 0); +} + +// allocator 1 + +template +struct allocator1 +{ + typedef T value_type; + ALLOCATOR_METHODS(allocator1) + + typedef yes_type propagate_on_container_copy_assignment; + typedef yes_type propagate_on_container_move_assignment; + typedef yes_type propagate_on_container_swap; + + allocator1 select_on_container_copy_construction() const { + ++selected; + return allocator1(); + } +}; + +void test_allocator1() +{ + typedef allocator1 allocator; + typedef boost::unordered::detail::allocator_traits traits; + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + 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() == 1); +} + +// allocator 2 + +template +struct allocator2 +{ + typedef T value_type; + typedef T* pointer; + typedef T const* const_pointer; + typedef std::size_t size_type; + + ALLOCATOR_METHODS(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 select_on_container_copy_construction() { + ++selected; + return allocator2(); + } +}; + +void test_allocator2() +{ + typedef allocator2 allocator; + typedef boost::unordered::detail::allocator_traits traits; + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + 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() == 0); +} + +// allocator 3 + +template +struct ptr +{ + T* value_; + + ptr(void* v) : value_((T*) v) {} + T& operator*() const { return *value_; } +}; + +template +struct allocator3 +{ + typedef T value_type; + typedef ptr pointer; + typedef ptr const_pointer; + typedef unsigned short size_type; + + ALLOCATOR_METHODS_TYPEDEFS(allocator3) + + typedef yes_type propagate_on_container_copy_assignment; + typedef no_type propagate_on_container_move_assignment; + + allocator3 select_on_container_copy_construction() const { + ++selected; + return allocator3(); + } +}; + +void test_allocator3() +{ + typedef allocator3 allocator; + typedef boost::unordered::detail::allocator_traits traits; + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same >)); + BOOST_MPL_ASSERT((boost::is_same >)); + BOOST_MPL_ASSERT((boost::is_same)); + 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() == 1); +} + +int main() +{ + test_empty_allocator(); + test_allocator1(); + test_allocator2(); + test_allocator3(); + return boost::report_errors(); +} diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 8abc63b9..2ea3a40a 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -514,6 +514,85 @@ UNORDERED_AUTO_TEST(insert_initializer_list_multimap) #endif +struct overloaded_constructor +{ + overloaded_constructor(int x1 = 1, int x2 = 2, int x3 = 3, int x4 = 4) + : x1(x1), x2(x2), x3(x3), x4(x4) {} + + int x1, x2, x3, x4; + + bool operator==(overloaded_constructor const& rhs) const + { + return x1 == rhs.x1 && x2 == rhs.x2 && x3 == rhs.x3 && x4 == rhs.x4; + } + + friend std::size_t hash_value(overloaded_constructor const& x) + { + std::size_t hash = 0; + boost::hash_combine(hash, x.x1); + boost::hash_combine(hash, x.x2); + boost::hash_combine(hash, x.x3); + boost::hash_combine(hash, x.x4); + return hash; + } +}; + +// 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)); +} + +UNORDERED_AUTO_TEST(set_emplace_test) +{ + boost::unordered_set x; + overloaded_constructor check; + + x.emplace(); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(1); + check = overloaded_constructor(1); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(2, 3); + check = overloaded_constructor(2, 3); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(4, 5, 6); + check = overloaded_constructor(4, 5, 6); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(7, 8, 9, 10); + check = overloaded_constructor(7, 8, 9, 10); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); +} + } RUN_TESTS() diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index fe97dcfe..6ebfd8b5 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -341,7 +341,10 @@ namespace unnecessary_copy_tests x.emplace(source >()); COPY_COUNT(2); MOVE_COUNT(source_pair_cost); -#if !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) +#if (defined(__GNUC__) && __GNUC__ > 4) || \ + (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \ + (defined(BOOST_MSVC) && BOOST_MSVC >= 1600 ) || \ + (!defined(__GNUC__) && !defined(BOOST_MSVC)) count_copies part; reset(); std::pair a_ref(part, part);