From f02990aebc4dfcc08570065586a2315aed367b90 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Wed, 4 Jun 2014 19:57:30 +0400 Subject: [PATCH 1/4] Added initial implementation of move_if_noexcept --- include/boost/move/traits.hpp | 10 ++++ include/boost/move/utility.hpp | 103 +++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/include/boost/move/traits.hpp b/include/boost/move/traits.hpp index ced1cdd..068f021 100644 --- a/include/boost/move/traits.hpp +++ b/include/boost/move/traits.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES @@ -55,6 +56,15 @@ struct has_nothrow_move namespace move_detail { +template +struct has_nothrow_move_or_uncopyable + : public ::boost::move_detail::integral_constant + < bool + , has_nothrow_move::value || + !boost::is_copy_constructible::value + > +{}; + // Code from Jeffrey Lee Hellrung, many thanks #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES diff --git a/include/boost/move/utility.hpp b/include/boost/move/utility.hpp index 964500e..33c861f 100644 --- a/include/boost/move/utility.hpp +++ b/include/boost/move/utility.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) @@ -80,6 +81,56 @@ return x; } + ////////////////////////////////////////////////////////////////////////////// + // + // move_if_noexcept() + // + ////////////////////////////////////////////////////////////////////////////// + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && !has_move_emulation_enabled::value, T&>::type + move_if_noexcept(T& x) BOOST_NOEXCEPT + { + return x; + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && ::boost::move_detail::has_nothrow_move_or_uncopyable::value, rv&>::type + move_if_noexcept(T& x) BOOST_NOEXCEPT + { + return *static_cast* >(::boost::move_detail::addressof(x)); + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && ::boost::move_detail::has_nothrow_move_or_uncopyable::value, rv&>::type + move_if_noexcept(rv& x) BOOST_NOEXCEPT + { + return x; + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&>::type + move_if_noexcept(T& x) BOOST_NOEXCEPT + { + return x; + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&>::type + move_if_noexcept(rv& x) BOOST_NOEXCEPT + { + return x; + } + } //namespace boost #else //#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) @@ -91,6 +142,7 @@ using ::std::move; using ::std::forward; + using ::std::move_if_noexcept; } //namespace boost @@ -183,6 +235,57 @@ #endif //BOOST_MOVE_DOXYGEN_INVOKED + ////////////////////////////////////////////////////////////////////////////// + // + // move_if_noexcept() + // + ////////////////////////////////////////////////////////////////////////////// + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + //! This function provides a way to convert a reference into a rvalue reference + //! in compilers with rvalue references. For other compilers converts T & into + //! ::boost::rv & so that move emulation is activated. Reference + //! would be converted to rvalue reference only if input type is nothrow move + //! constructible or if it has no copy constructor. + template + rvalue_reference move_if_noexcept(input_reference) noexcept; + + #elif defined(BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES) + + //Old move approach, lvalues could bind to rvalue references + template + inline typename ::boost::move_detail::enable_if_c + < ::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename remove_reference::type&&>::type + move_if_noexcept(T& x) BOOST_NOEXCEPT + { + return ::boost::move(x); + } + + template + inline typename ::boost::move_detail::enable_if_c + < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename remove_reference::type&>::type + move_if_noexcept(T& x) BOOST_NOEXCEPT + { + return x; + } + + #else //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES + template + inline typename ::boost::move_detail::enable_if_c + < ::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&&>::type + move_if_noexcept(T& x) BOOST_NOEXCEPT + { + return ::boost::move(x); + } + + template + inline typename ::boost::move_detail::enable_if_c + < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&>::type + move_if_noexcept(T& x) BOOST_NOEXCEPT + { + return x; + } + #endif //BOOST_MOVE_DOXYGEN_INVOKED + } //namespace boost { #endif //#if defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE) From 688c5726f80edbbb0f5240ed82915a8fc4be80e2 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Fri, 6 Jun 2014 12:43:34 +0400 Subject: [PATCH 2/4] Add tests for move_if_noexcept --- test/move_if_noexcept.cpp | 228 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 test/move_if_noexcept.cpp diff --git a/test/move_if_noexcept.cpp b/test/move_if_noexcept.cpp new file mode 100644 index 0000000..805af51 --- /dev/null +++ b/test/move_if_noexcept.cpp @@ -0,0 +1,228 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Antony Polukhin 2014. +// 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) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#include +#include +#include "../example/movable.hpp" +#include "../example/copymovable.hpp" +#include + +////////////////////////////////////////////////////////////////////////////// +//A copy_movable_noexcept class +class copy_movable_noexcept +{ + BOOST_COPYABLE_AND_MOVABLE(copy_movable_noexcept) + int value_; + + public: + copy_movable_noexcept() : value_(1){} + + //Move constructor and assignment + copy_movable_noexcept(BOOST_RV_REF(copy_movable_noexcept) m) + { value_ = m.value_; m.value_ = 0; } + + copy_movable_noexcept(const copy_movable_noexcept &m) + { value_ = m.value_; } + + copy_movable_noexcept & operator=(BOOST_RV_REF(copy_movable_noexcept) m) + { value_ = m.value_; m.value_ = 0; return *this; } + + copy_movable_noexcept & operator=(BOOST_COPY_ASSIGN_REF(copy_movable_noexcept) m) + { value_ = m.value_; return *this; } + + bool moved() const //Observer + { return value_ == 0; } +}; + +namespace boost{ + +template<> +struct has_nothrow_move +{ + static const bool value = true; +}; + +} //namespace boost{ + +////////////////////////////////////////////////////////////////////////////// +//A movable_throwable class +class movable_throwable +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_throwable) + int value_; + + public: + movable_throwable() : value_(1){} + + //Move constructor and assignment + movable_throwable(BOOST_RV_REF(movable_throwable) m) + { value_ = m.value_; m.value_ = 0; } + + movable_throwable & operator=(BOOST_RV_REF(movable_throwable) m) + { value_ = m.value_; m.value_ = 0; return *this; } + + bool moved() const //Observer + { return !value_; } + + int value() const //Observer + { return value_; } +}; + + +////////////////////////////////////////////////////////////////////////////// +// Helper functions +movable function(movable m) +{ + return movable(boost::move_if_noexcept(m)); +} + +copy_movable function(copy_movable m) +{ + return copy_movable(boost::move_if_noexcept(m)); +} + +copy_movable_noexcept function(copy_movable_noexcept m) +{ + return copy_movable_noexcept(boost::move_if_noexcept(m)); +} + +movable_throwable function(movable_throwable m) +{ + return movable_throwable(boost::move_if_noexcept(m)); +} + +movable functionr(BOOST_RV_REF(movable) m) +{ + return movable(boost::move_if_noexcept(m)); +} + +movable function2(movable m) +{ + return boost::move_if_noexcept(m); +} + +BOOST_RV_REF(movable) function2r(BOOST_RV_REF(movable) m) +{ + return boost::move_if_noexcept(m); +} + +movable move_return_function2 () +{ + return movable(); +} + +movable move_return_function () +{ + movable m; + return (boost::move_if_noexcept(m)); +} + +#define BOOST_CHECK(x) if (!(x)) { return __LINE__; } + +int main() +{ + { + movable m; + movable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + movable m3(function(movable(boost::move_if_noexcept(m2)))); + BOOST_CHECK(m2.moved()); + movable m4(function(boost::move_if_noexcept(m3))); + BOOST_CHECK(m3.moved()); + BOOST_CHECK(!m4.moved()); + } + { + movable m; + movable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + movable m3(functionr(movable(boost::move_if_noexcept(m2)))); + BOOST_CHECK(m2.moved()); + movable m4(functionr(boost::move_if_noexcept(m3))); + BOOST_CHECK(m3.moved()); + BOOST_CHECK(!m4.moved()); + } + { + movable m; + movable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + movable m3(function2(movable(boost::move_if_noexcept(m2)))); + BOOST_CHECK(m2.moved()); + movable m4(function2(boost::move_if_noexcept(m3))); + BOOST_CHECK(m3.moved()); + BOOST_CHECK(!m4.moved()); + } + { + movable m; + movable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + movable m3(function2r(movable(boost::move_if_noexcept(m2)))); + BOOST_CHECK(m2.moved()); + movable m4(function2r(boost::move_if_noexcept(m3))); + BOOST_CHECK(m3.moved()); + BOOST_CHECK(!m4.moved()); + } + { + movable m; + movable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + BOOST_CHECK(!m2.moved()); + movable m3(move_return_function()); + BOOST_CHECK(!m3.moved()); + } + { + movable m; + movable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + BOOST_CHECK(!m2.moved()); + movable m3(move_return_function2()); + BOOST_CHECK(!m3.moved()); + } + + // copy_movable may throw during move, so it must be copied + { + copy_movable m; + copy_movable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(!m.moved()); + copy_movable m3(function(copy_movable(boost::move_if_noexcept(m2)))); + BOOST_CHECK(!m2.moved()); + copy_movable m4(function(boost::move_if_noexcept(m3))); + BOOST_CHECK(!m3.moved()); + BOOST_CHECK(!m4.moved()); + } + + + // copy_movable_noexcept can not throw during move + { + copy_movable_noexcept m; + copy_movable_noexcept m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + copy_movable_noexcept m3(function(copy_movable_noexcept(boost::move_if_noexcept(m2)))); + BOOST_CHECK(m2.moved()); + copy_movable_noexcept m4(function(boost::move_if_noexcept(m3))); + BOOST_CHECK(m3.moved()); + BOOST_CHECK(!m4.moved()); + } + + // movable_throwable can not throw during move but it has no copy constructor + { + movable_throwable m; + movable_throwable m2(boost::move_if_noexcept(m)); + BOOST_CHECK(m.moved()); + movable_throwable m3(function(movable_throwable(boost::move_if_noexcept(m2)))); + BOOST_CHECK(m2.moved()); + movable_throwable m4(function(boost::move_if_noexcept(m3))); + BOOST_CHECK(m3.moved()); + BOOST_CHECK(!m4.moved()); + } + + return 0; +} + +#include From c60351de0ff225a741e995ad1d0ed8b57be5458f Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Mon, 23 Jun 2014 12:35:41 +0400 Subject: [PATCH 3/4] Fix move_if_noexcept: add const to reference --- include/boost/move/utility.hpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/include/boost/move/utility.hpp b/include/boost/move/utility.hpp index 33c861f..80b2716 100644 --- a/include/boost/move/utility.hpp +++ b/include/boost/move/utility.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) @@ -89,7 +90,7 @@ template inline typename ::boost::move_detail::enable_if_c - < enable_move_utility_emulation::value && !has_move_emulation_enabled::value, T&>::type + < enable_move_utility_emulation::value && !has_move_emulation_enabled::value, typename add_const::type & >::type move_if_noexcept(T& x) BOOST_NOEXCEPT { return x; @@ -116,7 +117,7 @@ template inline typename ::boost::move_detail::enable_if_c < enable_move_utility_emulation::value && has_move_emulation_enabled::value - && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&>::type + && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename add_const::type & >::type move_if_noexcept(T& x) BOOST_NOEXCEPT { return x; @@ -125,7 +126,7 @@ template inline typename ::boost::move_detail::enable_if_c < enable_move_utility_emulation::value && has_move_emulation_enabled::value - && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&>::type + && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename add_const::type & >::type move_if_noexcept(rv& x) BOOST_NOEXCEPT { return x; @@ -245,7 +246,8 @@ //! in compilers with rvalue references. For other compilers converts T & into //! ::boost::rv & so that move emulation is activated. Reference //! would be converted to rvalue reference only if input type is nothrow move - //! constructible or if it has no copy constructor. + //! constructible or if it has no copy constructor. In all other cases const + //! reference would be returned template rvalue_reference move_if_noexcept(input_reference) noexcept; @@ -262,7 +264,9 @@ template inline typename ::boost::move_detail::enable_if_c - < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename remove_reference::type&>::type + < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, + typename add_const::type>::type& + >::type move_if_noexcept(T& x) BOOST_NOEXCEPT { return x; @@ -279,7 +283,7 @@ template inline typename ::boost::move_detail::enable_if_c - < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&>::type + < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename add_const::type & >::type move_if_noexcept(T& x) BOOST_NOEXCEPT { return x; From 3c56780e0e67b8f16339cce5a4899b861801f031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Mon, 18 Aug 2014 02:03:35 +0200 Subject: [PATCH 4/4] - Splitted utility.hpp into utility_core.hpp and utility.hpp. The first one implements move() and forward() minimizing external dependencies. utility.hpp includes utility_core.hpp and implemente move_if_noexcept.cpp - Changed move_if_noexcept with a single function - Changed test case to use boost/core/lightweight_test.hpp - Added boost::is_nothrow_move_constructible::value to is_nothrow_move_constructible_or_uncopyable so types with only a non-throwing move constructor is forwarded with move_if_noexcept. - --- doc/move.qbk | 11 +- include/boost/move/core.hpp | 4 +- include/boost/move/detail/meta_utils.hpp | 25 +++ include/boost/move/move.hpp | 2 +- include/boost/move/traits.hpp | 7 +- include/boost/move/utility.hpp | 209 +++-------------------- include/boost/move/utility_core.hpp | 197 +++++++++++++++++++++ proj/vc7ide/Move.sln | 9 + proj/vc7ide/move_if_noexcept_test.vcproj | 135 +++++++++++++++ test/move_if_noexcept.cpp | 3 +- 10 files changed, 407 insertions(+), 195 deletions(-) create mode 100644 include/boost/move/utility_core.hpp create mode 100644 proj/vc7ide/move_if_noexcept_test.vcproj diff --git a/doc/move.qbk b/doc/move.qbk index c32c0fe..824b725 100644 --- a/doc/move.qbk +++ b/doc/move.qbk @@ -757,16 +757,19 @@ Many thanks to all boosters that have tested, reviewed and improved the library. [section:release_notes_boost_1_57_00 Boost 1.57 Release] -* Fixed bug [@https://svn.boost.org/trac/boost/ticket/9785 Trac #9785: ['"Compiler warning with intel icc in boost/move/core.hpp"]], +* Added `move_if_noexcept` utility. Thanks to Antony Polukhin for the implementation. +* Fixed bugs: + * [@https://svn.boost.org/trac/boost/ticket/9785 Trac #9785: ['"Compiler warning with intel icc in boost/move/core.hpp"]], [endsect] [section:release_notes_boost_1_56_00 Boost 1.56 Release] * Added [macroref BOOST_MOVE_RET BOOST_MOVE_RET]. -* Fixed bug [@https://svn.boost.org/trac/boost/ticket/9482 #9482: ['"MSVC macros not undefined in boost/move/detail/config_end.hpp"]], - [@https://svn.boost.org/trac/boost/ticket/9045 #9045: ['"Wrong macro name on docs"]], - [@https://svn.boost.org/trac/boost/ticket/8420 #8420: ['"move's is_convertible does not compile with aligned data"]]. +* Fixed bugs: + * [@https://svn.boost.org/trac/boost/ticket/9482 #9482: ['"MSVC macros not undefined in boost/move/detail/config_end.hpp"]], + * [@https://svn.boost.org/trac/boost/ticket/9045 #9045: ['"Wrong macro name on docs"]], + * [@https://svn.boost.org/trac/boost/ticket/8420 #8420: ['"move's is_convertible does not compile with aligned data"]]. [endsect] diff --git a/include/boost/move/core.hpp b/include/boost/move/core.hpp index de034e6..dada893 100644 --- a/include/boost/move/core.hpp +++ b/include/boost/move/core.hpp @@ -9,7 +9,7 @@ // ////////////////////////////////////////////////////////////////////////////// -//! \file core.hpp +//! \file //! This header implements macros to define movable classes and //! move-aware functions @@ -20,7 +20,7 @@ //boost_move_no_copy_constructor_or_assign typedef //used to detect noncopyable types for other Boost libraries. -#ifdef BOOST_NO_CXX11_DELETED_FUNCTIONS +#if defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) #define BOOST_MOVE_IMPL_NO_COPY_CTOR_OR_ASSIGN(TYPE) \ private:\ TYPE(TYPE &);\ diff --git a/include/boost/move/detail/meta_utils.hpp b/include/boost/move/detail/meta_utils.hpp index c95d7cf..096705e 100644 --- a/include/boost/move/detail/meta_utils.hpp +++ b/include/boost/move/detail/meta_utils.hpp @@ -133,6 +133,7 @@ struct remove_reference typedef T type; }; + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template @@ -143,6 +144,30 @@ struct remove_reference #endif +//add_const +template +struct add_const +{ + typedef const T type; +}; + +template +struct add_const +{ + typedef T& type; +}; + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +template +struct add_const +{ + typedef T&& type; +}; + +#endif + + template struct is_class_or_union { diff --git a/include/boost/move/move.hpp b/include/boost/move/move.hpp index 66e99a7..5a22d31 100644 --- a/include/boost/move/move.hpp +++ b/include/boost/move/move.hpp @@ -10,7 +10,7 @@ // ////////////////////////////////////////////////////////////////////////////// -//! \file move.hpp +//! \file //! A general library header that includes //! the rest of top-level headers. diff --git a/include/boost/move/traits.hpp b/include/boost/move/traits.hpp index 068f021..0ec5d4a 100644 --- a/include/boost/move/traits.hpp +++ b/include/boost/move/traits.hpp @@ -57,10 +57,13 @@ struct has_nothrow_move namespace move_detail { template -struct has_nothrow_move_or_uncopyable +struct is_nothrow_move_constructible_or_uncopyable : public ::boost::move_detail::integral_constant < bool - , has_nothrow_move::value || + //The standard requires is_nothrow_move_constructible for move_if_noexcept + //but a user (usually in C++03) might specialize has_nothrow_move which includes it + , boost::is_nothrow_move_constructible::value || + has_nothrow_move::value || !boost::is_copy_constructible::value > {}; diff --git a/include/boost/move/utility.hpp b/include/boost/move/utility.hpp index 8a8867c..5e6f213 100644 --- a/include/boost/move/utility.hpp +++ b/include/boost/move/utility.hpp @@ -10,79 +10,20 @@ ////////////////////////////////////////////////////////////////////////////// //! \file +//! This header includes core utilities from and defines +//! some more advanced utilities such as: #ifndef BOOST_MOVE_MOVE_UTILITY_HPP #define BOOST_MOVE_MOVE_UTILITY_HPP #include -#include -#include -#include +#include #include -#include #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) namespace boost { - template - struct enable_move_utility_emulation - { - static const bool value = true; - }; - - ////////////////////////////////////////////////////////////////////////////// - // - // move() - // - ////////////////////////////////////////////////////////////////////////////// - - template - inline typename ::boost::move_detail::enable_if_c - < enable_move_utility_emulation::value && !has_move_emulation_enabled::value, T&>::type - move(T& x) BOOST_NOEXCEPT - { - return x; - } - - template - inline typename ::boost::move_detail::enable_if_c - < enable_move_utility_emulation::value && has_move_emulation_enabled::value, rv&>::type - move(T& x) BOOST_NOEXCEPT - { - return *static_cast* >(::boost::move_detail::addressof(x)); - } - - template - inline typename ::boost::move_detail::enable_if_c - < enable_move_utility_emulation::value && has_move_emulation_enabled::value, rv&>::type - move(rv& x) BOOST_NOEXCEPT - { - return x; - } - - ////////////////////////////////////////////////////////////////////////////// - // - // forward() - // - ////////////////////////////////////////////////////////////////////////////// - - template - inline typename ::boost::move_detail::enable_if_c - < enable_move_utility_emulation::value && ::boost::move_detail::is_rv::value, T &>::type - forward(const typename ::boost::move_detail::identity::type &x) BOOST_NOEXCEPT - { - return const_cast(x); - } - - template - inline typename ::boost::move_detail::enable_if_c - < enable_move_utility_emulation::value && !::boost::move_detail::is_rv::value, const T &>::type - forward(const typename ::boost::move_detail::identity::type &x) BOOST_NOEXCEPT - { - return x; - } - ////////////////////////////////////////////////////////////////////////////// // // move_if_noexcept() @@ -91,7 +32,9 @@ template inline typename ::boost::move_detail::enable_if_c - < enable_move_utility_emulation::value && !has_move_emulation_enabled::value, typename add_const::type & >::type + < enable_move_utility_emulation::value && !has_move_emulation_enabled::value + , typename ::boost::move_detail::add_const::type & + >::type move_if_noexcept(T& x) BOOST_NOEXCEPT { return x; @@ -100,7 +43,7 @@ template inline typename ::boost::move_detail::enable_if_c < enable_move_utility_emulation::value && has_move_emulation_enabled::value - && ::boost::move_detail::has_nothrow_move_or_uncopyable::value, rv&>::type + && ::boost::move_detail::is_nothrow_move_constructible_or_uncopyable::value, rv&>::type move_if_noexcept(T& x) BOOST_NOEXCEPT { return *static_cast* >(::boost::move_detail::addressof(x)); @@ -109,7 +52,9 @@ template inline typename ::boost::move_detail::enable_if_c < enable_move_utility_emulation::value && has_move_emulation_enabled::value - && ::boost::move_detail::has_nothrow_move_or_uncopyable::value, rv&>::type + && ::boost::move_detail::is_nothrow_move_constructible_or_uncopyable::value + , rv& + >::type move_if_noexcept(rv& x) BOOST_NOEXCEPT { return x; @@ -118,7 +63,9 @@ template inline typename ::boost::move_detail::enable_if_c < enable_move_utility_emulation::value && has_move_emulation_enabled::value - && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename add_const::type & >::type + && !::boost::move_detail::is_nothrow_move_constructible_or_uncopyable::value + , typename ::boost::move_detail::add_const::type & + >::type move_if_noexcept(T& x) BOOST_NOEXCEPT { return x; @@ -127,7 +74,9 @@ template inline typename ::boost::move_detail::enable_if_c < enable_move_utility_emulation::value && has_move_emulation_enabled::value - && !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename add_const::type & >::type + && !::boost::move_detail::is_nothrow_move_constructible_or_uncopyable::value + , typename ::boost::move_detail::add_const::type & + >::type move_if_noexcept(rv& x) BOOST_NOEXCEPT { return x; @@ -142,8 +91,6 @@ namespace boost{ - using ::std::move; - using ::std::forward; using ::std::move_if_noexcept; } //namespace boost @@ -152,90 +99,6 @@ namespace boost { - //! This trait's internal boolean `value` is false in compilers with rvalue references - //! and true in compilers without rvalue references. - //! - //! A user can specialize this trait for a type T to false to SFINAE out `move` and `forward` - //! so that the user can define a different move emulation for that type in namespace boost - //! (e.g. another Boost library for its types) and avoid any overload ambiguity. - template - struct enable_move_utility_emulation - { - static const bool value = false; - }; - - ////////////////////////////////////////////////////////////////////////////// - // - // move - // - ////////////////////////////////////////////////////////////////////////////// - - #if defined(BOOST_MOVE_DOXYGEN_INVOKED) - //! This function provides a way to convert a reference into a rvalue reference - //! in compilers with rvalue references. For other compilers converts T & into - //! ::boost::rv & so that move emulation is activated. - template - rvalue_reference move(input_reference) noexcept; - - #elif defined(BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES) - - //Old move approach, lvalues could bind to rvalue references - template - inline typename ::boost::move_detail::remove_reference::type && move(T&& t) BOOST_NOEXCEPT - { return t; } - - #else //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - - template - inline typename ::boost::move_detail::remove_reference::type && move(T&& t) BOOST_NOEXCEPT - { return static_cast::type &&>(t); } - - #endif //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - - ////////////////////////////////////////////////////////////////////////////// - // - // forward - // - ////////////////////////////////////////////////////////////////////////////// - - - #if defined(BOOST_MOVE_DOXYGEN_INVOKED) - //! This function provides limited form of forwarding that is usually enough for - //! in-place construction and avoids the exponential overloading for - //! achieve the limited forwarding in C++03. - //! - //! For compilers with rvalue references this function provides perfect forwarding. - //! - //! Otherwise: - //! * If input_reference binds to const ::boost::rv & then it output_reference is - //! ::boost::rv & - //! - //! * Else, output_reference is equal to input_reference. - template output_reference forward(input_reference) noexcept; - #elif defined(BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES) - - //Old move approach, lvalues could bind to rvalue references - - template - inline T&& forward(typename ::boost::move_detail::identity::type&& t) BOOST_NOEXCEPT - { return t; } - - #else //Old move - - template - inline T&& forward(typename ::boost::move_detail::remove_reference::type& t) BOOST_NOEXCEPT - { return static_cast(t); } - - template - inline T&& forward(typename ::boost::move_detail::remove_reference::type&& t) BOOST_NOEXCEPT - { - //"boost::forward error: 'T' is a lvalue reference, can't forward as rvalue."; - BOOST_STATIC_ASSERT(!boost::move_detail::is_lvalue_reference::value); - return static_cast(t); - } - - #endif //BOOST_MOVE_DOXYGEN_INVOKED - ////////////////////////////////////////////////////////////////////////////// // // move_if_noexcept() @@ -251,43 +114,19 @@ template rvalue_reference move_if_noexcept(input_reference) noexcept; - #elif defined(BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES) - - //Old move approach, lvalues could bind to rvalue references - template - inline typename ::boost::move_detail::enable_if_c - < ::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename remove_reference::type&&>::type - move_if_noexcept(T& x) BOOST_NOEXCEPT - { - return ::boost::move(x); - } - - template - inline typename ::boost::move_detail::enable_if_c - < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, - typename add_const::type>::type& - >::type - move_if_noexcept(T& x) BOOST_NOEXCEPT - { - return x; - } - #else //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES - template - inline typename ::boost::move_detail::enable_if_c - < ::boost::move_detail::has_nothrow_move_or_uncopyable::value, T&&>::type - move_if_noexcept(T& x) BOOST_NOEXCEPT - { - return ::boost::move(x); - } template - inline typename ::boost::move_detail::enable_if_c - < !::boost::move_detail::has_nothrow_move_or_uncopyable::value, typename add_const::type & >::type - move_if_noexcept(T& x) BOOST_NOEXCEPT + inline typename ::boost::move_detail::if_c + < ::boost::move_detail::is_nothrow_move_constructible_or_uncopyable::value + , T&& + , const T& + >::type + move_if_noexcept(T& x) BOOST_NOEXCEPT { - return x; + return ::boost::move(x); } + #endif //BOOST_MOVE_DOXYGEN_INVOKED } //namespace boost { diff --git a/include/boost/move/utility_core.hpp b/include/boost/move/utility_core.hpp new file mode 100644 index 0000000..236f9a9 --- /dev/null +++ b/include/boost/move/utility_core.hpp @@ -0,0 +1,197 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2012. +// 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) +// +// See http://www.boost.org/libs/move for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//! \file +//! This header defines core utilities to ease the development +//! of move-aware functions. This header minimizes dependencies +//! from other libraries. + +#ifndef BOOST_MOVE_MOVE_UTILITY_CORE_HPP +#define BOOST_MOVE_MOVE_UTILITY_CORE_HPP + +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) + + namespace boost { + + template + struct enable_move_utility_emulation + { + static const bool value = true; + }; + + ////////////////////////////////////////////////////////////////////////////// + // + // move() + // + ////////////////////////////////////////////////////////////////////////////// + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && !has_move_emulation_enabled::value, T&>::type + move(T& x) BOOST_NOEXCEPT + { + return x; + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && has_move_emulation_enabled::value, rv&>::type + move(T& x) BOOST_NOEXCEPT + { + return *static_cast* >(::boost::move_detail::addressof(x)); + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && has_move_emulation_enabled::value, rv&>::type + move(rv& x) BOOST_NOEXCEPT + { + return x; + } + + ////////////////////////////////////////////////////////////////////////////// + // + // forward() + // + ////////////////////////////////////////////////////////////////////////////// + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && ::boost::move_detail::is_rv::value, T &>::type + forward(const typename ::boost::move_detail::identity::type &x) BOOST_NOEXCEPT + { + return const_cast(x); + } + + template + inline typename ::boost::move_detail::enable_if_c + < enable_move_utility_emulation::value && !::boost::move_detail::is_rv::value, const T &>::type + forward(const typename ::boost::move_detail::identity::type &x) BOOST_NOEXCEPT + { + return x; + } + + } //namespace boost + +#else //#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_MOVE_DOXYGEN_INVOKED) + + #if defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE) + #include + + namespace boost{ + + using ::std::move; + using ::std::forward; + + } //namespace boost + + #else //!BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE + + namespace boost { + + //! This trait's internal boolean `value` is false in compilers with rvalue references + //! and true in compilers without rvalue references. + //! + //! A user can specialize this trait for a type T to false to SFINAE out `move` and `forward` + //! so that the user can define a different move emulation for that type in namespace boost + //! (e.g. another Boost library for its types) and avoid any overload ambiguity. + template + struct enable_move_utility_emulation + { + static const bool value = false; + }; + + ////////////////////////////////////////////////////////////////////////////// + // + // move + // + ////////////////////////////////////////////////////////////////////////////// + + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + //! This function provides a way to convert a reference into a rvalue reference + //! in compilers with rvalue references. For other compilers converts T & into + //! ::boost::rv & so that move emulation is activated. + template + rvalue_reference move(input_reference) noexcept; + + #elif defined(BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES) + + //Old move approach, lvalues could bind to rvalue references + template + inline typename ::boost::move_detail::remove_reference::type && move(T&& t) BOOST_NOEXCEPT + { return t; } + + #else //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES + + template + inline typename ::boost::move_detail::remove_reference::type && move(T&& t) BOOST_NOEXCEPT + { return static_cast::type &&>(t); } + + #endif //BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES + + ////////////////////////////////////////////////////////////////////////////// + // + // forward + // + ////////////////////////////////////////////////////////////////////////////// + + + #if defined(BOOST_MOVE_DOXYGEN_INVOKED) + //! This function provides limited form of forwarding that is usually enough for + //! in-place construction and avoids the exponential overloading for + //! achieve the limited forwarding in C++03. + //! + //! For compilers with rvalue references this function provides perfect forwarding. + //! + //! Otherwise: + //! * If input_reference binds to const ::boost::rv & then it output_reference is + //! ::boost::rv & + //! + //! * Else, output_reference is equal to input_reference. + template output_reference forward(input_reference) noexcept; + #elif defined(BOOST_MOVE_OLD_RVALUE_REF_BINDING_RULES) + + //Old move approach, lvalues could bind to rvalue references + + template + inline T&& forward(typename ::boost::move_detail::identity::type&& t) BOOST_NOEXCEPT + { return t; } + + #else //Old move + + template + inline T&& forward(typename ::boost::move_detail::remove_reference::type& t) BOOST_NOEXCEPT + { return static_cast(t); } + + template + inline T&& forward(typename ::boost::move_detail::remove_reference::type&& t) BOOST_NOEXCEPT + { + //"boost::forward error: 'T' is a lvalue reference, can't forward as rvalue."; + BOOST_STATIC_ASSERT(!boost::move_detail::is_lvalue_reference::value); + return static_cast(t); + } + + #endif //BOOST_MOVE_DOXYGEN_INVOKED + + } //namespace boost { + + #endif //#if defined(BOOST_MOVE_USE_STANDARD_LIBRARY_MOVE) + +#endif //BOOST_NO_CXX11_RVALUE_REFERENCES + +#include + +#endif //#ifndef BOOST_MOVE_MOVE_UTILITY_CORE_HPP diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index a27c40a..cdb3f54 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -63,6 +63,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_move_return", "doc_move ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "move_if_noexcept_test", "move_if_noexcept_test.vcproj", "{CD57C283-1862-42FE-BF87-B96D3A2A7912}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -135,6 +139,10 @@ Global {7C1462C8-D532-4B8E-F2F6-E3A2A796D912}.Debug.Build.0 = Debug|Win32 {7C1462C8-D532-4B8E-F2F6-E3A2A796D912}.Release.ActiveCfg = Release|Win32 {7C1462C8-D532-4B8E-F2F6-E3A2A796D912}.Release.Build.0 = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.ActiveCfg = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Debug.Build.0 = Debug|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.ActiveCfg = Release|Win32 + {CD57C283-1862-42FE-BF87-B96D3A2A7912}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution ..\..\..\..\boost\move\algorithm.hpp = ..\..\..\..\boost\move\algorithm.hpp @@ -149,6 +157,7 @@ Global ..\..\..\..\boost\move\detail\move_helpers.hpp = ..\..\..\..\boost\move\detail\move_helpers.hpp ..\..\..\..\boost\move\traits.hpp = ..\..\..\..\boost\move\traits.hpp ..\..\..\..\boost\move\utility.hpp = ..\..\..\..\boost\move\utility.hpp + ..\..\..\..\boost\move\utility_core.hpp = ..\..\..\..\boost\move\utility_core.hpp EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection diff --git a/proj/vc7ide/move_if_noexcept_test.vcproj b/proj/vc7ide/move_if_noexcept_test.vcproj new file mode 100644 index 0000000..ac38316 --- /dev/null +++ b/proj/vc7ide/move_if_noexcept_test.vcproj @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/move_if_noexcept.cpp b/test/move_if_noexcept.cpp index 805af51..5f8124b 100644 --- a/test/move_if_noexcept.cpp +++ b/test/move_if_noexcept.cpp @@ -10,6 +10,7 @@ ////////////////////////////////////////////////////////////////////////////// #include #include +#include #include "../example/movable.hpp" #include "../example/copymovable.hpp" #include @@ -222,7 +223,7 @@ int main() BOOST_CHECK(!m4.moved()); } - return 0; + return boost::report_errors(); } #include