diff --git a/doc/move.qbk b/doc/move.qbk index dbd7d11..372b374 100644 --- a/doc/move.qbk +++ b/doc/move.qbk @@ -532,19 +532,26 @@ care to achieve portable and efficient code when using the library with C++03 co [section:emulation_limitations_base Initializing base classes] When initializing base classes in move constructors, users must -cast the reference to a base class reference before moving it. Example: +cast the reference to a base class reference before moving it or just +use `BOOST_MOVE_BASE`. Example: [c++] - //Portable and efficient Derived(BOOST_RV_REF(Derived) x) // Move ctor - : Base(boost::move(static_cast(x))), - mem_(boost::move(x.mem_)) { } + : Base(boost::move(static_cast(x))) + //... +or + +[c++] + + Derived(BOOST_RV_REF(Derived) x) // Move ctor + : Base(BOOST_MOVE_BASE(Base, x)) + //... If casting is not performed the emulation will not move construct -the base class, because no conversion is available from `BOOST_RV_REF(Derived)` -to `BOOST_RV_REF(Base)`. Without the cast we might obtain a compilation +the base class, because no conversion is available from `BOOST_RV_REF(Derived)` to +`BOOST_RV_REF(Base)`. Without the cast or `BOOST_MOVE_BASE` we might obtain a compilation error (for non-copyable types) or a less-efficient move constructor (for copyable types): [c++] @@ -552,8 +559,8 @@ error (for non-copyable types) or a less-efficient move constructor (for copyabl //If Derived is copyable, then Base is copy-constructed. //If not, a compilation error is issued Derived(BOOST_RV_REF(Derived) x) // Move ctor - : Base(boost::move(x)), - mem_(boost::move(x.mem_)) { } + : Base(boost::move(x)) + //... [endsect] @@ -755,6 +762,13 @@ Many thanks to all boosters that have tested, reviewed and improved the library. [section:release_notes Release Notes] +[section:release_notes_boost_1_58_00 Boost 1.58 Release] + +* Added [macroref BOOST_MOVE_BASE BOOST_MOVE_BASE] utility. +* Added [funcref boost::adl_move_swap adl_move_swap] utility. + +[endsect] + [section:release_notes_boost_1_57_00 Boost 1.57 Release] * Added `unique_ptr` smart pointer. Thanks to Howard Hinnant for his excellent unique_ptr emulation code and testsuite. diff --git a/example/doc_clone_ptr.cpp b/example/doc_clone_ptr.cpp index 8842e38..e0fa73c 100644 --- a/example/doc_clone_ptr.cpp +++ b/example/doc_clone_ptr.cpp @@ -64,19 +64,19 @@ class Derived : public Base // Compiler-generated copy constructor... Derived(BOOST_RV_REF(Derived) x) // Move ctor - : Base(boost::move(static_cast(x))), + : Base(BOOST_MOVE_BASE(Base, x)), mem_(boost::move(x.mem_)) { } Derived& operator=(BOOST_RV_REF(Derived) x) // Move assign { - Base::operator=(boost::move(static_cast(x))); - mem_ = boost::move(x.mem_); + Base::operator=(BOOST_MOVE_BASE(Base, x)); + mem_ = boost::move(x.mem_); return *this; } Derived& operator=(BOOST_COPY_ASSIGN_REF(Derived) x) // Copy assign { - Base::operator=(static_cast(x)); + Base::operator=(x); mem_ = x.mem_; return *this; } diff --git a/include/boost/move/adl_move_swap.hpp b/include/boost/move/adl_move_swap.hpp new file mode 100644 index 0000000..a3373a1 --- /dev/null +++ b/include/boost/move/adl_move_swap.hpp @@ -0,0 +1,225 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright 2007, 2008 Steven Watanabe, Joseph Gauterin, Niels Dekker +// (C) Copyright Ion Gaztanaga 2005-2013. 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/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP +#define BOOST_MOVE_ADL_MOVE_SWAP_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +//Based on Boost.Core's swap. +//Many thanks to Steven Watanabe, Joseph Gauterin and Niels Dekker. + +#include +#include //for std::size_t + +//Try to avoid including , as it's quite big +#if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) + #include //Dinkum libraries define std::swap in utility which is lighter than algorithm +#elif defined(BOOST_GCC) && defined(BOOST_GNU_STDLIB) + #if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) + #include //algobase is lighter than + #elif ((__GNUC__ == 4) && (__GNUC_MINOR__ == 3)) + //In GCC 4.3 a tiny stl_move.h was created with swap and move utilities + #include + #else + //In GCC 4.4 stl_move.h was renamed to move.h + #include + #endif +#elif defined(_LIBCPP_VERSION) + #include //The initial import of libc++ defines std::swap and still there +#else //Fallback + #include +#endif + +#include //for boost::move + +#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +namespace boost_move_member_swap { + +struct dont_care +{ + dont_care(...); +}; + +struct private_type +{ + static private_type p; + private_type const &operator,(int) const; +}; + +typedef char yes_type; +struct no_type{ char dummy[2]; }; + +template +no_type is_private_type(T const &); + +yes_type is_private_type(private_type const &); + +template +class has_member_function_named_swap +{ + struct BaseMixin + { + void swap(); + }; + + struct Base : public Type, public BaseMixin { Base(); }; + template class Helper{}; + + template + static no_type deduce(U*, Helper* = 0); + static yes_type deduce(...); + + public: + static const bool value = sizeof(yes_type) == sizeof(deduce((Base*)(0))); +}; + +template +struct has_member_swap_impl +{ + static const bool value = false; +}; + +template +struct has_member_swap_impl +{ + struct FunWrap : Fun + { + FunWrap(); + + using Fun::swap; + private_type swap(dont_care) const; + }; + + static Fun &declval_fun(); + static FunWrap declval_wrap(); + + static bool const value = + sizeof(no_type) == sizeof(is_private_type( (declval_wrap().swap(declval_fun()), 0)) ); +}; + +template +struct has_member_swap : public has_member_swap_impl + ::value> +{}; + +} //namespace boost_move_member_swap + +namespace boost_move_adl_swap{ + +template +struct and_op_impl +{ static const bool value = false; }; + +template +struct and_op_impl +{ static const bool value = P2::value; }; + +template +struct and_op + : and_op_impl +{}; + +////// + +template +struct and_op_not_impl +{ static const bool value = false; }; + +template +struct and_op_not_impl +{ static const bool value = !P2::value; }; + +template +struct and_op_not + : and_op_not_impl +{}; + +template +void swap_proxy(T& x, T& y, typename boost::move_detail::enable_if_c::value>::type* = 0) +{ + //use std::swap if argument dependent lookup fails + //Use using directive ("using namespace xxx;") instead as some older compilers + //don't do ADL with using declarations ("using ns::func;"). + using namespace std; + swap(x, y); +} + +template +void swap_proxy(T& x, T& y + , typename boost::move_detail::enable_if< and_op_not_impl + , boost_move_member_swap::has_member_swap > + >::type* = 0) +{ T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t); } + +template +void swap_proxy(T& x, T& y + , typename boost::move_detail::enable_if< and_op_impl< boost::move_detail::has_move_emulation_enabled_impl + , boost_move_member_swap::has_member_swap > + >::type* = 0) +{ x.swap(y); } + +} //namespace boost_move_adl_swap{ + +#else + +namespace boost_move_adl_swap{ + +template +void swap_proxy(T& x, T& y) +{ + using std::swap; + swap(x, y); +} + +} //namespace boost_move_adl_swap{ + +#endif //#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +namespace boost_move_adl_swap{ + +template +void swap_proxy(T (& x)[N], T (& y)[N]) +{ + for (std::size_t i = 0; i < N; ++i){ + ::boost_move_adl_swap::swap_proxy(x[i], y[i]); + } +} + +} //namespace boost_move_adl_swap { + +#endif //!defined(BOOST_MOVE_DOXYGEN_INVOKED) + +namespace boost{ + +//! Exchanges the values of a and b, using Argument Dependent Lookup (ADL) to select a +//! specialized swap function if available. If no specialized swap function is available, +//! std::swap is used. +//! +//! Exception: If T uses Boost.Move's move emulation and the compiler has +//! no rvalue references then: +//! +//! - If T has a T::swap(T&) member, that member is called. +//! - Otherwise a move-based swap is called, equivalent to: +//! T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t);. +template +void adl_move_swap(T& x, T& y) +{ + ::boost_move_adl_swap::swap_proxy(x, y); +} + +} //namespace boost{ + +#endif //#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP diff --git a/include/boost/move/algorithm.hpp b/include/boost/move/algorithm.hpp index f5f4b81..bb628c6 100644 --- a/include/boost/move/algorithm.hpp +++ b/include/boost/move/algorithm.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_ALGORITHM_HPP #define BOOST_MOVE_ALGORITHM_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include diff --git a/include/boost/move/core.hpp b/include/boost/move/core.hpp index 4728a71..113a95d 100644 --- a/include/boost/move/core.hpp +++ b/include/boost/move/core.hpp @@ -16,6 +16,10 @@ #ifndef BOOST_MOVE_CORE_HPP #define BOOST_MOVE_CORE_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include //boost_move_no_copy_constructor_or_assign typedef @@ -194,6 +198,10 @@ boost::move_detail::move_return< RET_TYPE >(REF) // + #define BOOST_MOVE_BASE(BASE_TYPE, ARG) \ + ::boost::move((BASE_TYPE&)(ARG)) + // + ////////////////////////////////////////////////////////////////////////////// // // BOOST_MOVABLE_BUT_NOT_COPYABLE @@ -369,7 +377,6 @@ const TYPE & \ // - #endif //#if !defined(BOOST_MOVE_DOXYGEN_INVOKED) #if !defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) @@ -432,6 +439,17 @@ #endif //!defined(BOOST_MOVE_MSVC_AUTO_MOVE_RETURN_BUG) || defined(BOOST_MOVE_DOXYGEN_INVOKED) + //!This macro is used to achieve portable optimal move constructors. + //! + //!When implementing the move constructor, in C++03 compilers the moved-from argument must be + //!cast to the base type before calling `::boost::move()` due to rvalue reference limitations. + //! + //!In C++11 compilers the cast from a rvalue reference of a derived type to a rvalue reference of + //!a base type is implicit. + #define BOOST_MOVE_BASE(BASE_TYPE, ARG) \ + ::boost::move((BASE_TYPE&)(ARG)) + // + namespace boost { namespace move_detail { diff --git a/include/boost/move/default_delete.hpp b/include/boost/move/default_delete.hpp index d8494e8..a367674 100644 --- a/include/boost/move/default_delete.hpp +++ b/include/boost/move/default_delete.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_MOVE_DEFAULT_DELETE_HPP_INCLUDED #define BOOST_MOVE_DEFAULT_DELETE_HPP_INCLUDED +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/detail/meta_utils.hpp b/include/boost/move/detail/meta_utils.hpp index 0df0086..a23c8dc 100644 --- a/include/boost/move/detail/meta_utils.hpp +++ b/include/boost/move/detail/meta_utils.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP #define BOOST_MOVE_DETAIL_META_UTILS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include //for std::size_t diff --git a/include/boost/move/detail/move_helpers.hpp b/include/boost/move/detail/move_helpers.hpp index 78d98ea..a97bea6 100644 --- a/include/boost/move/detail/move_helpers.hpp +++ b/include/boost/move/detail/move_helpers.hpp @@ -12,6 +12,10 @@ #ifndef BOOST_MOVE_MOVE_HELPERS_HPP #define BOOST_MOVE_MOVE_HELPERS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include diff --git a/include/boost/move/detail/unique_ptr_meta_utils.hpp b/include/boost/move/detail/unique_ptr_meta_utils.hpp index 42fd272..50c6e01 100644 --- a/include/boost/move/detail/unique_ptr_meta_utils.hpp +++ b/include/boost/move/detail/unique_ptr_meta_utils.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_UNIQUE_PTR_DETAIL_META_UTILS_HPP #define BOOST_MOVE_UNIQUE_PTR_DETAIL_META_UTILS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include //for std::size_t //Small meta-typetraits to support move diff --git a/include/boost/move/detail/workaround.hpp b/include/boost/move/detail/workaround.hpp index 1bf879c..3906f32 100644 --- a/include/boost/move/detail/workaround.hpp +++ b/include/boost/move/detail/workaround.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_MOVE_DETAIL_WORKAROUND_HPP #define BOOST_MOVE_DETAIL_WORKAROUND_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #define BOOST_MOVE_PERFECT_FORWARDING #endif diff --git a/include/boost/move/iterator.hpp b/include/boost/move/iterator.hpp index dda6f83..eaf83ef 100644 --- a/include/boost/move/iterator.hpp +++ b/include/boost/move/iterator.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_ITERATOR_HPP #define BOOST_MOVE_ITERATOR_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include //std::iterator diff --git a/include/boost/move/make_unique.hpp b/include/boost/move/make_unique.hpp index 59cfafa..fb57850 100644 --- a/include/boost/move/make_unique.hpp +++ b/include/boost/move/make_unique.hpp @@ -11,6 +11,10 @@ #ifndef BOOST_MOVE_MAKE_UNIQUE_HPP_INCLUDED #define BOOST_MOVE_MAKE_UNIQUE_HPP_INCLUDED +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/move.hpp b/include/boost/move/move.hpp index 5a22d31..be3fffc 100644 --- a/include/boost/move/move.hpp +++ b/include/boost/move/move.hpp @@ -17,6 +17,10 @@ #ifndef BOOST_MOVE_MOVE_HPP #define BOOST_MOVE_MOVE_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/traits.hpp b/include/boost/move/traits.hpp index c4b3afe..4e29006 100644 --- a/include/boost/move/traits.hpp +++ b/include/boost/move/traits.hpp @@ -14,6 +14,10 @@ #ifndef BOOST_MOVE_MOVE_TRAITS_HPP #define BOOST_MOVE_MOVE_TRAITS_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index df10fb3..48fa275 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -11,11 +11,16 @@ #ifndef BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED #define BOOST_MOVE_UNIQUE_PTR_HPP_INCLUDED +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include #include #include +#include #include #include @@ -723,9 +728,8 @@ class unique_ptr //! Effects: Invokes swap on the stored pointers and on the stored deleters of *this and u. void swap(unique_ptr& u) BOOST_NOEXCEPT { - using ::boost::move_detail::swap; - swap(m_data.m_p, u.m_data.m_p); - swap(m_data.deleter(), u.m_data.deleter()); + ::boost::adl_move_swap(m_data.m_p, u.m_data.m_p); + ::boost::adl_move_swap(m_data.deleter(), u.m_data.deleter()); } }; diff --git a/include/boost/move/utility.hpp b/include/boost/move/utility.hpp index a1ddd26..955734c 100644 --- a/include/boost/move/utility.hpp +++ b/include/boost/move/utility.hpp @@ -16,6 +16,10 @@ #ifndef BOOST_MOVE_MOVE_UTILITY_HPP #define BOOST_MOVE_MOVE_UTILITY_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include diff --git a/include/boost/move/utility_core.hpp b/include/boost/move/utility_core.hpp index ae17fd3..8d09e2a 100644 --- a/include/boost/move/utility_core.hpp +++ b/include/boost/move/utility_core.hpp @@ -17,6 +17,10 @@ #ifndef BOOST_MOVE_MOVE_UTILITY_CORE_HPP #define BOOST_MOVE_MOVE_UTILITY_CORE_HPP +#if defined(_MSC_VER) +# pragma once +#endif + #include #include #include @@ -273,14 +277,6 @@ namespace boost{ namespace move_detail{ -template -void swap(T &a, T &b) -{ - T c((::boost::move(a))); - a = ::boost::move(b); - b = ::boost::move(c); -} - template typename boost::move_detail::add_rvalue_reference::type declval(); diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index c12681b..8429ad4 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -103,6 +103,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unique_ptr_types_test", "un ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adl_move_swap", "adl_move_swap.vcproj", "{CD2617A8-79EB-6172-2CE4-26617AA3AC93}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -215,8 +219,13 @@ Global {C57C28A3-4FE0-6208-BF87-B2B61D3A7675}.Debug.Build.0 = Debug|Win32 {C57C28A3-4FE0-6208-BF87-B2B61D3A7675}.Release.ActiveCfg = Release|Win32 {C57C28A3-4FE0-6208-BF87-B2B61D3A7675}.Release.Build.0 = Release|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Debug.ActiveCfg = Debug|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Debug.Build.0 = Debug|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Release.ActiveCfg = Release|Win32 + {CD2617A8-79EB-6172-2CE4-26617AA3AC93}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution + ..\..\..\..\boost\move\adl_move_swap.hpp = ..\..\..\..\boost\move\adl_move_swap.hpp ..\..\..\..\boost\move\algorithm.hpp = ..\..\..\..\boost\move\algorithm.hpp ..\..\..\..\boost\move\detail\config_begin.hpp = ..\..\..\..\boost\move\detail\config_begin.hpp ..\..\..\..\boost\move\detail\config_end.hpp = ..\..\..\..\boost\move\detail\config_end.hpp diff --git a/proj/vc7ide/adl_move_swap.vcproj b/proj/vc7ide/adl_move_swap.vcproj new file mode 100644 index 0000000..4c57491 --- /dev/null +++ b/proj/vc7ide/adl_move_swap.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/adl_move_swap.cpp b/test/adl_move_swap.cpp new file mode 100644 index 0000000..863e893 --- /dev/null +++ b/test/adl_move_swap.cpp @@ -0,0 +1,268 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-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 + +class swap_stats +{ + public: + static void reset_stats() + { + member_swap_calls = 0; + friend_swap_calls = 0; + move_cnstor_calls = 0; + move_assign_calls = 0; + copy_cnstor_calls = 0; + copy_assign_calls = 0; + } + + static unsigned int member_swap_calls; + static unsigned int friend_swap_calls; + static unsigned int move_cnstor_calls; + static unsigned int move_assign_calls; + static unsigned int copy_cnstor_calls; + static unsigned int copy_assign_calls; +}; + +unsigned int swap_stats::member_swap_calls = 0; +unsigned int swap_stats::friend_swap_calls = 0; +unsigned int swap_stats::move_cnstor_calls = 0; +unsigned int swap_stats::move_assign_calls = 0; +unsigned int swap_stats::copy_cnstor_calls = 0; +unsigned int swap_stats::copy_assign_calls = 0; + +class movable : public swap_stats +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable) + public: + movable() {} + movable(BOOST_RV_REF(movable)) { ++move_cnstor_calls; } + movable & operator=(BOOST_RV_REF(movable)){ ++move_assign_calls; return *this; } + friend void swap(movable &, movable &) { ++friend_swap_calls; } +}; + +class movable_swap_member : public swap_stats +{ + BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_swap_member) + public: + movable_swap_member() {} + movable_swap_member(BOOST_RV_REF(movable_swap_member)) { ++move_cnstor_calls; } + movable_swap_member & operator=(BOOST_RV_REF(movable_swap_member)){ ++move_assign_calls; return *this; } + void swap(movable_swap_member &) { ++member_swap_calls; } + friend void swap(movable_swap_member &, movable_swap_member &) { ++friend_swap_calls; } +}; + +class copyable : public swap_stats +{ + public: + copyable() {} + copyable(const copyable &) { ++copy_cnstor_calls; } + copyable & operator=(const copyable&) { ++copy_assign_calls; return *this; } + void swap(copyable &) { ++member_swap_calls; } + friend void swap(copyable &, copyable &) { ++friend_swap_calls; } +}; + +class no_swap : public swap_stats +{ + private: unsigned m_state; + public: + explicit no_swap(unsigned i): m_state(i){} + no_swap(const no_swap &x) { m_state = x.m_state; ++copy_cnstor_calls; } + no_swap & operator=(const no_swap& x) { m_state = x.m_state; ++copy_assign_calls; return *this; } + void swap(no_swap &) { ++member_swap_calls; } + friend bool operator==(const no_swap &x, const no_swap &y) { return x.m_state == y.m_state; } + friend bool operator!=(const no_swap &x, const no_swap &y) { return !(x==y); } +}; + + +int main() +{ + { //movable + movable x, y; + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + #if defined(BOOST_NO_RVALUE_REFERENCES) + //In non rvalue reference compilers, + //movable classes with no swap() member uses + //boost::move() to implement swap. + BOOST_TEST(swap_stats::friend_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 1); + BOOST_TEST(swap_stats::move_assign_calls == 2); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #else + //In compilers with rvalue references, this should call friend swap via ADL + BOOST_TEST(swap_stats::friend_swap_calls == 1); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #endif + } + { //movable_swap_member + movable_swap_member x, y; + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + #if defined(BOOST_NO_RVALUE_REFERENCES) + //In non rvalue reference compilers, + //movable classes with no swap() member uses + //boost::move() to implement swap. + BOOST_TEST(swap_stats::friend_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 1); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #else + //In compilers with rvalue references, this should call friend swap via ADL + BOOST_TEST(swap_stats::friend_swap_calls == 1); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + #endif + } + { //copyable + copyable x, y; + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + //This should call friend swap via ADL + BOOST_TEST(swap_stats::friend_swap_calls == 1); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 0); + BOOST_TEST(swap_stats::copy_assign_calls == 0); + } + { //no_swap + no_swap x(1), y(2), x_back(x), y_back(y); + swap_stats::reset_stats(); + ::boost::adl_move_swap(x, y); + //This should call std::swap which uses copies + BOOST_TEST(swap_stats::friend_swap_calls == 0); + BOOST_TEST(swap_stats::member_swap_calls == 0); + BOOST_TEST(swap_stats::move_cnstor_calls == 0); + BOOST_TEST(swap_stats::move_assign_calls == 0); + BOOST_TEST(swap_stats::copy_cnstor_calls == 1); + BOOST_TEST(swap_stats::copy_assign_calls == 2); + BOOST_TEST(x == y_back); + BOOST_TEST(y == x_back); + BOOST_TEST(x != y); + } + return ::boost::report_errors(); +} +#include + +/* +#include + +namespace boost_move_member_swap { + +struct dont_care +{ + dont_care(...); +}; + +struct private_type +{ + static private_type p; + private_type const &operator,(int) const; +}; + +typedef char yes_type; +struct no_type{ char dummy[2]; }; + +template +no_type is_private_type(T const &); + +yes_type is_private_type(private_type const &); + +template +class has_member_function_named_swap +{ + struct BaseMixin + { + void swap(); + }; + + struct Base : public Type, public BaseMixin { Base(); }; + template class Helper{}; + + template + static no_type deduce(U*, Helper* = 0); + static yes_type deduce(...); + + public: + static const bool value = sizeof(yes_type) == sizeof(deduce((Base*)(0))); +}; + +template +struct has_member_swap_impl +{ + static const bool value = false; +}; + +template +struct has_member_swap_impl +{ + struct FunWrap : Fun + { + FunWrap(); + + using Fun::swap; + private_type swap(dont_care) const; + }; + + static Fun &declval_fun(); + static FunWrap declval_wrap(); + + static bool const value = + sizeof(no_type) == sizeof(is_private_type( (declval_wrap().swap(declval_fun()), 0)) ); +}; + +template +struct has_member_swap : public has_member_swap_impl + ::value> +{}; + +} //namespace boost_move_member_swap + +class noswap +{ + public: + void swap(); +}; + +class noneswap +{ +}; + +class yesswap +{ + public: + void swap(yesswap&); +}; + +int main() +{ + BOOST_TEST(!boost_move_member_swap::has_member_swap::value); + BOOST_TEST(boost_move_member_swap::has_member_swap::value); + BOOST_TEST(!boost_move_member_swap::has_member_swap::value); + return boost::report_errors(); +} +*/ \ No newline at end of file diff --git a/test/unique_ptr_modifiers.cpp b/test/unique_ptr_modifiers.cpp index b67d4f5..3de952d 100644 --- a/test/unique_ptr_modifiers.cpp +++ b/test/unique_ptr_modifiers.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include ////////////////////////////////////////////// @@ -284,7 +285,7 @@ void test() BOOST_TEST(s2.get() == p2); BOOST_TEST(*s2 == A(2)); BOOST_TEST(s2.get_deleter().state() == 2); - swap(s1, s2); + boost::adl_move_swap(s1, s2); BOOST_TEST(s1.get() == p2); BOOST_TEST(*s1 == A(2)); BOOST_TEST(s1.get_deleter().state() == 2);