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);