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