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 ced1cdd..0ec5d4a 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,18 @@ struct has_nothrow_move namespace move_detail { +template +struct is_nothrow_move_constructible_or_uncopyable + : public ::boost::move_detail::integral_constant + < bool + //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 + > +{}; + // 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 d4219a1..5e6f213 100644 --- a/include/boost/move/utility.hpp +++ b/include/boost/move/utility.hpp @@ -10,73 +10,74 @@ ////////////////////////////////////////////////////////////////////////////// //! \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 #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() + // 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(T& x) BOOST_NOEXCEPT + < 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; } 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 + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && ::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)); } 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 + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && ::boost::move_detail::is_nothrow_move_constructible_or_uncopyable::value + , rv& + >::type + move_if_noexcept(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 + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && !::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 const_cast(x); + return 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 + < enable_move_utility_emulation::value && has_move_emulation_enabled::value + && !::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; } @@ -90,8 +91,7 @@ namespace boost{ - using ::std::move; - using ::std::forward; + using ::std::move_if_noexcept; } //namespace boost @@ -99,89 +99,35 @@ 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 + // 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. + //! ::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. In all other cases const + //! reference would be returned 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; } + rvalue_reference move_if_noexcept(input_reference) noexcept; #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 + 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 { - //"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); + return ::boost::move(x); } - #endif //BOOST_MOVE_DOXYGEN_INVOKED + #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 new file mode 100644 index 0000000..5f8124b --- /dev/null +++ b/test/move_if_noexcept.cpp @@ -0,0 +1,229 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 +#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 boost::report_errors(); +} + +#include