diff --git a/doc/container.qbk b/doc/container.qbk index 1cf3f89..d802f5d 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1234,6 +1234,8 @@ use [*Boost.Container]? There are several reasons for that: * Implemented C++17 `insert_or_assign`/`try_emplace` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. * Implemented C++17 `extract`/`insert(node)` for [classref boost::container::map map], [classref boost::container::multimap multimap], [classref boost::container::set set], [classref boost::container::multiset multiset]. +* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf P0084R2 Emplace Return Type] + in `deque`, `vector`, `stable_vector`, `small_vector`, `static_vector`, `list` and `slist`. [endsect] diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 4659dff..255cd93 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -1348,44 +1348,52 @@ class deque : protected deque_base //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the beginning of the deque. //! + //! Returns: A reference to the created object. + //! //! Throws: If memory allocation throws or the in-place constructor throws. //! //! Complexity: Amortized constant time template - void emplace_front(BOOST_FWD_REF(Args)... args) + reference emplace_front(BOOST_FWD_REF(Args)... args) { if(this->priv_push_front_simple_available()){ + reference r = *this->priv_push_front_simple_pos(); allocator_traits_type::construct ( this->alloc() , this->priv_push_front_simple_pos() , boost::forward(args)...); this->priv_push_front_simple_commit(); + return r; } else{ typedef container_detail::insert_nonmovable_emplace_proxy type; - this->priv_insert_front_aux_impl(1, type(boost::forward(args)...)); + return *this->priv_insert_front_aux_impl(1, type(boost::forward(args)...)); } } //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the end of the deque. //! + //! Returns: A reference to the created object. + //! //! Throws: If memory allocation throws or the in-place constructor throws. //! //! Complexity: Amortized constant time template - void emplace_back(BOOST_FWD_REF(Args)... args) + reference emplace_back(BOOST_FWD_REF(Args)... args) { if(this->priv_push_back_simple_available()){ + reference r = *this->priv_push_back_simple_pos(); allocator_traits_type::construct ( this->alloc() , this->priv_push_back_simple_pos() , boost::forward(args)...); this->priv_push_back_simple_commit(); + return r; } else{ typedef container_detail::insert_nonmovable_emplace_proxy type; - this->priv_insert_back_aux_impl(1, type(boost::forward(args)...)); + return *this->priv_insert_back_aux_impl(1, type(boost::forward(args)...)); } } @@ -1420,32 +1428,36 @@ class deque : protected deque_base #define BOOST_CONTAINER_DEQUE_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ - void emplace_front(BOOST_MOVE_UREF##N)\ + reference emplace_front(BOOST_MOVE_UREF##N)\ {\ if(priv_push_front_simple_available()){\ + reference r = *this->priv_push_front_simple_pos();\ allocator_traits_type::construct\ ( this->alloc(), this->priv_push_front_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ priv_push_front_simple_commit();\ + return r;\ }\ else{\ typedef container_detail::insert_nonmovable_emplace_proxy##N\ type;\ - priv_insert_front_aux_impl(1, type(BOOST_MOVE_FWD##N));\ + return *priv_insert_front_aux_impl(1, type(BOOST_MOVE_FWD##N));\ }\ }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ - void emplace_back(BOOST_MOVE_UREF##N)\ + reference emplace_back(BOOST_MOVE_UREF##N)\ {\ if(priv_push_back_simple_available()){\ + reference r = *this->priv_push_back_simple_pos();\ allocator_traits_type::construct\ ( this->alloc(), this->priv_push_back_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ priv_push_back_simple_commit();\ + return r;\ }\ else{\ typedef container_detail::insert_nonmovable_emplace_proxy##N\ type;\ - priv_insert_back_aux_impl(1, type(BOOST_MOVE_FWD##N));\ + return *priv_insert_back_aux_impl(1, type(BOOST_MOVE_FWD##N));\ }\ }\ \ diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index a034910..f779cc4 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -709,24 +709,28 @@ class list //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the end of the list. //! + //! Returns: A reference to the created object. + //! //! Throws: If memory allocation throws or //! T's in-place constructor throws. //! //! Complexity: Constant template - void emplace_back(BOOST_FWD_REF(Args)... args) - { this->emplace(this->cend(), boost::forward(args)...); } + reference emplace_back(BOOST_FWD_REF(Args)... args) + { return *this->emplace(this->cend(), boost::forward(args)...); } //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the beginning of the list. //! + //! Returns: A reference to the created object. + //! //! Throws: If memory allocation throws or //! T's in-place constructor throws. //! //! Complexity: Constant template - void emplace_front(BOOST_FWD_REF(Args)... args) - { this->emplace(this->cbegin(), boost::forward(args)...); } + reference emplace_front(BOOST_FWD_REF(Args)... args) + { return *this->emplace(this->cbegin(), boost::forward(args)...); } //! Effects: Inserts an object of type T constructed with //! std::forward(args)... before p. @@ -747,12 +751,12 @@ class list #define BOOST_CONTAINER_LIST_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - void emplace_back(BOOST_MOVE_UREF##N)\ - { this->emplace(this->cend() BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ + reference emplace_back(BOOST_MOVE_UREF##N)\ + { return *this->emplace(this->cend() BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - void emplace_front(BOOST_MOVE_UREF##N)\ - { this->emplace(this->cbegin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\ + reference emplace_front(BOOST_MOVE_UREF##N)\ + { return *this->emplace(this->cbegin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ iterator emplace(const_iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 06863d6..3a1d66b 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -714,13 +714,15 @@ class slist //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the front of the list //! + //! Returns: A reference to the created object. + //! //! Throws: If memory allocation throws or //! T's copy constructor throws. //! //! Complexity: Amortized constant time. template - void emplace_front(BOOST_FWD_REF(Args)... args) - { this->emplace_after(this->cbefore_begin(), boost::forward(args)...); } + reference emplace_front(BOOST_FWD_REF(Args)... args) + { return *this->emplace_after(this->cbefore_begin(), boost::forward(args)...); } //! Effects: Inserts an object of type T constructed with //! std::forward(args)... after prev @@ -740,8 +742,8 @@ class slist #define BOOST_CONTAINER_SLIST_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - void emplace_front(BOOST_MOVE_UREF##N)\ - { this->emplace_after(this->cbefore_begin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\ + reference emplace_front(BOOST_MOVE_UREF##N)\ + { return *this->emplace_after(this->cbefore_begin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ iterator emplace_after(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index fccf766..5d6dc0f 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -1374,16 +1374,18 @@ class stable_vector //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the end of the stable_vector. //! + //! Returns: A reference to the created object. + //! //! Throws: If memory allocation throws or the in-place constructor throws. //! //! Complexity: Amortized constant time. template - void emplace_back(Args &&...args) + reference emplace_back(Args &&...args) { typedef emplace_functor EmplaceFunctor; typedef emplace_iterator EmplaceIterator; EmplaceFunctor &&ef = EmplaceFunctor(boost::forward(args)...); - this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); + return *this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); } //! Requires: p must be a valid iterator of *this. @@ -1411,13 +1413,13 @@ class stable_vector #define BOOST_CONTAINER_STABLE_VECTOR_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - void emplace_back(BOOST_MOVE_UREF##N)\ + reference emplace_back(BOOST_MOVE_UREF##N)\ {\ typedef emplace_functor##N\ BOOST_MOVE_LT##N BOOST_MOVE_TARG##N BOOST_MOVE_GT##N EmplaceFunctor;\ typedef emplace_iterator EmplaceIterator;\ EmplaceFunctor ef BOOST_MOVE_LP##N BOOST_MOVE_FWD##N BOOST_MOVE_RP##N;\ - this->insert(this->cend() , EmplaceIterator(ef), EmplaceIterator());\ + return *this->insert(this->cend() , EmplaceIterator(ef), EmplaceIterator());\ }\ \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index ea6b030..21168cb 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -677,6 +677,8 @@ public: //! @brief Inserts a Value constructed with //! \c std::forward(args)... in the end of the container. //! + //! @return A reference to the created object. + //! //! @param args The arguments of the constructor of the new element which will be created at the end of the container. //! //! @par Throws @@ -685,7 +687,7 @@ public: //! @par Complexity //! Constant O(1). template - void emplace_back(Args &&...args); + reference emplace_back(Args &&...args); //! @pre //! @li \c p must be a valid iterator of \c *this in range [begin(), end()] diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 6621efc..5d4ab30 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -1724,21 +1724,24 @@ class vector //! Effects: Inserts an object of type T constructed with //! std::forward(args)... in the end of the vector. //! + //! Returns: A reference to the created object. + //! //! Throws: If memory allocation throws or the in-place constructor throws or //! T's copy/move constructor throws. //! //! Complexity: Amortized constant time. template - BOOST_CONTAINER_FORCEINLINE void emplace_back(BOOST_FWD_REF(Args)...args) + BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_FWD_REF(Args)...args) { if (BOOST_LIKELY(this->room_enough())){ //There is more memory, just construct a new object at the end allocator_traits_type::construct(this->m_holder.alloc(), this->priv_raw_end(), ::boost::forward(args)...); ++this->m_holder.m_size; + return *this->priv_raw_end(); } else{ typedef container_detail::insert_emplace_proxy type; - this->priv_forward_range_insert_no_capacity + return *this->priv_forward_range_insert_no_capacity (this->back_ptr(), 1, type(::boost::forward(args)...), alloc_version()); } } @@ -1787,16 +1790,17 @@ class vector #define BOOST_CONTAINER_VECTOR_EMPLACE_CODE(N) \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ - BOOST_CONTAINER_FORCEINLINE void emplace_back(BOOST_MOVE_UREF##N)\ + BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_MOVE_UREF##N)\ {\ if (BOOST_LIKELY(this->room_enough())){\ allocator_traits_type::construct (this->m_holder.alloc()\ , this->priv_raw_end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ ++this->m_holder.m_size;\ + return *this->priv_raw_end();\ }\ else{\ typedef container_detail::insert_emplace_proxy_arg##N type;\ - this->priv_forward_range_insert_no_capacity\ + return *this->priv_forward_range_insert_no_capacity\ ( this->back_ptr(), 1, type(BOOST_MOVE_FWD##N), alloc_version());\ }\ }\ diff --git a/test/emplace_test.hpp b/test/emplace_test.hpp index 50fe656..c6a75dc 100644 --- a/test/emplace_test.hpp +++ b/test/emplace_test.hpp @@ -175,13 +175,18 @@ bool test_emplace_back(container_detail::true_) new(&expected [4]) EmplaceInt(1, 2, 3, 4); new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); Container c; - c.emplace_back(); - if(!test_expected_container(c, &expected[0], 1)){ - return false; + typedef typename Container::reference reference; + { + reference r = c.emplace_back(); + if(&r != &c.back() && !test_expected_container(c, &expected[0], 1)){ + return false; + } } - c.emplace_back(1); - if(!test_expected_container(c, &expected[0], 2)){ - return false; + { + reference r = c.emplace_back(1); + if(&r != &c.back() && !test_expected_container(c, &expected[0], 2)){ + return false; + } } c.emplace_back(1, 2); if(!test_expected_container(c, &expected[0], 3)){ @@ -222,13 +227,18 @@ bool test_emplace_front(container_detail::true_) new(&expected [4]) EmplaceInt(1); new(&expected [5]) EmplaceInt(); Container c; - c.emplace_front(); - if(!test_expected_container(c, &expected[0] + 5, 1)){ - return false; + typedef typename Container::reference reference; + { + reference r = c.emplace_front(); + if(&r != &c.front() && !test_expected_container(c, &expected[0] + 5, 1)){ + return false; + } } - c.emplace_front(1); - if(!test_expected_container(c, &expected[0] + 4, 2)){ - return false; + { + reference r = c.emplace_front(1); + if(&r != &c.front() && !test_expected_container(c, &expected[0] + 4, 2)){ + return false; + } } c.emplace_front(1, 2); if(!test_expected_container(c, &expected[0] + 3, 3)){