diff --git a/doc/container.qbk b/doc/container.qbk index 3d9fecb..cc70e52 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1216,7 +1216,8 @@ use [*Boost.Container]? There are several reasons for that: [section:release_notes_boost_1_62_00 Boost 1.62 Release] * Fixed bugs: - * [@https://svn.boost.org/trac/boost/ticket/9481 Trac #9481: ['"Minor comment typo in Boost.Container"]]. + * [@https://svn.boost.org/trac/boost/ticket/9481 Trac #9481: ['"Minor comment typo in Boost.Container"]]. + * [@https://svn.boost.org/trac/boost/ticket/9689 Trac #9689: ['"Add piecewise_construct to boost::container"]]. * [@https://svn.boost.org/trac/boost/ticket/11170 Trac #11170: ['"Doc slip for index_of"]]. * [@https://svn.boost.org/trac/boost/ticket/11802 Trac #11802: ['"Incorrect ordering after using insert() with ordered_range_t on a flat_multiset with a non-default sort order"]]. * [@https://svn.boost.org/trac/boost/ticket/12117 Trac #12117: ['"flat_set constructor with ordered_unique_range"]]. diff --git a/include/boost/container/detail/pair.hpp b/include/boost/container/detail/pair.hpp index f239b69..0bf39f7 100644 --- a/include/boost/container/detail/pair.hpp +++ b/include/boost/container/detail/pair.hpp @@ -28,13 +28,60 @@ #include #include #include +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +# include +#endif #include //swap #include //pair #include +#include + +namespace boost { +namespace tuples { + +struct null_type; + +} //namespace tuples { +} //namespace boost { + +#if defined(BOOST_MSVC) && (_CPPLIB_VER == 520) +//MSVC 2010 tuple marker +namespace std { namespace tr1 { struct _Nil; }} +#elif defined(BOOST_MSVC) && (_CPPLIB_VER == 540) +//MSVC 2012 tuple marker +namespace std { struct _Nil; } +#endif + namespace boost { namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + struct std_piecewise_construct_holder + { + static ::std::piecewise_construct_t *dummy; + }; + + template + ::std::piecewise_construct_t *std_piecewise_construct_holder::dummy; + +typedef const std::piecewise_construct_t & piecewise_construct_t; + +#else + +//! The piecewise_construct_t struct is an empty structure type used as a unique type to +//! disambiguate used to disambiguate between different functions that take two tuple arguments. +typedef unspecified piecewise_construct_t; + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! A instance of type +//! piecewise_construct_t +static piecewise_construct_t piecewise_construct = BOOST_CONTAINER_DOC1ST(unspecified, *std_piecewise_construct_holder<>::dummy); + namespace container_detail { template @@ -78,6 +125,9 @@ struct is_std_pair< std::pair > struct pair_nat; +template +void get(T); //to enable ADL + template struct pair { @@ -147,11 +197,86 @@ struct pair : first(::boost::move(p.first)), second(::boost::move(p.second)) {} - //piecewise_construct missing - //template pair(pair&& p); - //template - // pair(piecewise_construct_t, tuple first_args, - // tuple second_args); + //piecewise construction from boost::tuple + #define BOOST_PAIR_PIECEWISE_CONSTRUCT_BOOST_TUPLE_CODE(N,M)\ + template< template class BoostTuple \ + BOOST_MOVE_I_IF(BOOST_MOVE_OR(N,M)) BOOST_MOVE_CLASS##N BOOST_MOVE_I_IF(BOOST_MOVE_AND(N,M)) BOOST_MOVE_CLASSQ##M > \ + pair( piecewise_construct_t\ + , BoostTuple p\ + , BoostTuple q)\ + : first(BOOST_MOVE_TMPL_GET##N), second(BOOST_MOVE_TMPL_GETQ##M)\ + { (void)p; (void)q; }\ + // + BOOST_MOVE_ITER2D_0TOMAX(9, BOOST_PAIR_PIECEWISE_CONSTRUCT_BOOST_TUPLE_CODE) + #undef BOOST_PAIR_PIECEWISE_CONSTRUCT_BOOST_TUPLE_CODE + + //piecewise construction from variadic tuple (with delegating constructors) + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + # if !defined(BOOST_CONTAINER_NO_CXX11_DELEGATING_CONSTRUCTORS) + private: + template + pair(Tuple1& t1, Tuple2& t2, index_tuple, index_tuple) + : first (get(::boost::move(t1))...) + , second(get(::boost::move(t2))...) + { (void) t1; (void)t2; } + + public: + template class Tuple, class... Args1, class... Args2> + pair(piecewise_construct_t, Tuple t1, Tuple t2) + : pair(t1, t2, typename build_number_seq::type(), typename build_number_seq::type()) + {} + # else + //piecewise construction from variadic tuple (suboptimal, without delegating constructors) + private: + template class Tuple, typename... Args> + static T build_from_args(Tuple&& t) + { return do_build_from_args(::boost::move(t), typename build_number_seq::type()); } + + template class Tuple, typename... Args, std::size_t... Indexes> + static T do_build_from_args(Tuple && t, const index_tuple&) + { (void)t; return T(::boost::forward(get(t))...); } + + public: + template class Tuple, class... Args1, class... Args2> + pair(piecewise_construct_t, Tuple t1, Tuple t2) + : first (build_from_args (::boost::move(t1))) + , second (build_from_args(::boost::move(t2))) + {} + # endif //BOOST_NO_CXX11_VARIADIC_TEMPLATES + #elif defined(BOOST_MSVC) && (_CPPLIB_VER == 520) + //MSVC 2010 tuple implementation + #define BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE(N,M)\ + template< template class StdTuple \ + BOOST_MOVE_I_IF(BOOST_MOVE_OR(N,M)) BOOST_MOVE_CLASS##N BOOST_MOVE_I_IF(BOOST_MOVE_AND(N,M)) BOOST_MOVE_CLASSQ##M > \ + pair( piecewise_construct_t\ + , StdTuple p\ + , StdTuple q)\ + : first(BOOST_MOVE_GET_IDX##N), second(BOOST_MOVE_GET_IDXQ##M)\ + { (void)p; (void)q; }\ + // + BOOST_MOVE_ITER2D_0TOMAX(9, BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE) + #undef BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE + #elif defined(BOOST_MSVC) && (_CPPLIB_VER == 540) + #if _VARIADIC_MAX >= 9 + #define BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT 9 + #else + #define BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT BOOST_MOVE_ADD(_VARIADIC_MAX, 1) + #endif + + //MSVC 2012 tuple implementation + #define BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_CODE(N,M)\ + template< template class StdTuple \ + BOOST_MOVE_I_IF(BOOST_MOVE_OR(N,M)) BOOST_MOVE_CLASS##N BOOST_MOVE_I_IF(BOOST_MOVE_AND(N,M)) BOOST_MOVE_CLASSQ##M > \ + pair( piecewise_construct_t\ + , StdTuple p\ + , StdTuple q)\ + : first(BOOST_MOVE_GET_IDX##N), second(BOOST_MOVE_GET_IDXQ##M)\ + { (void)p; (void)q; }\ + // + BOOST_MOVE_ITER2D_0TOMAX(BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT, BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_CODE) + #undef BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE + #undef BOOST_PAIR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT + #endif //pair copy assignment pair& operator=(BOOST_COPY_ASSIGN_REF(pair) p) diff --git a/test/pair_test.cpp b/test/pair_test.cpp index dbfdb06..a3f10ec 100644 --- a/test/pair_test.cpp +++ b/test/pair_test.cpp @@ -12,6 +12,8 @@ #include "movable_int.hpp" #include "emplace_test.hpp" #include +#include +#include //non_copymovable_int //copyable_int @@ -19,6 +21,16 @@ //movable_and_copyable_int +#include + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) || (defined(BOOST_MSVC) && (BOOST_MSVC == 1700 || BOOST_MSVC == 1600)) +#define BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE +#endif + +#if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) +#include +#endif + using namespace ::boost::container; int main () @@ -47,8 +59,85 @@ int main () container_detail::pair p4(::boost::move(a), ::boost::move(b)); } } - //piecewise_construct missing... - return 0; + { //piecewise construct from boost tuple + using namespace boost::tuples; + { + boost::container::container_detail::pair p(piecewise_construct, tuple<>(), tuple<>()); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 0.f); + } + { + boost::container::container_detail::pair p(piecewise_construct, tuple<>(), tuple(2.f)); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 2.f); + } + { + boost::container::container_detail::pair p(piecewise_construct, tuple(2), tuple(1.f)); + BOOST_TEST(p.first == 2); + BOOST_TEST(p.second == 1.f); + } + { + boost::container::container_detail::pair + < boost::container::container_detail::pair + , boost::container::container_detail::pair + > p(piecewise_construct, tuple(3, 4.f), tuple(8.,'a')); + BOOST_TEST(p.first.first == 3); + BOOST_TEST(p.first.second == 4.f); + BOOST_TEST(p.second.first == 8.); + BOOST_TEST(p.second.second == 'a'); + } + { + boost::container::container_detail::pair + < tuple + , char + > p(piecewise_construct, tuple(3, 16.f, 32.), tuple('b')); + BOOST_TEST(p.first.get<0>() == 3); + BOOST_TEST(p.first.get<1>() == 16.f); + BOOST_TEST(p.first.get<2>() == 32.); + BOOST_TEST(p.second == 'b'); + } + } + #if defined(BOOST_CONTAINER_PAIR_TEST_HAS_HEADER_TUPLE) + { //piecewise construct from std tuple + using std::tuple; + { + boost::container::container_detail::pair p(piecewise_construct, tuple<>(), tuple<>()); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 0.f); + } + { + boost::container::container_detail::pair p(piecewise_construct, tuple<>(), tuple(2.f)); + BOOST_TEST(p.first == 0); + BOOST_TEST(p.second == 2.f); + } + { + boost::container::container_detail::pair p(piecewise_construct, tuple(2), tuple(1.f)); + BOOST_TEST(p.first == 2); + BOOST_TEST(p.second == 1.f); + } + { + boost::container::container_detail::pair + < boost::container::container_detail::pair + , boost::container::container_detail::pair + > p(piecewise_construct, tuple(3, 4.f), tuple(8.,'a')); + BOOST_TEST(p.first.first == 3); + BOOST_TEST(p.first.second == 4.f); + BOOST_TEST(p.second.first == 8.); + BOOST_TEST(p.second.second == 'a'); + } + { + boost::container::container_detail::pair + < tuple + , char + > p(piecewise_construct, tuple(3, 16.f, 32.), tuple('b')); + BOOST_TEST(std::get<0>(p.first) == 3); + BOOST_TEST(std::get<1>(p.first) == 16.f); + BOOST_TEST(std::get<2>(p.first) == 32.); + BOOST_TEST(p.second == 'b'); + } + } + #endif //#!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + return ::boost::report_errors(); } #include