diff --git a/doc/move.qbk b/doc/move.qbk index a47c27f..ea62f8b 100644 --- a/doc/move.qbk +++ b/doc/move.qbk @@ -661,6 +661,32 @@ An alternative is to implement a single `operator =()` for copyable and movable However, "pass by value" is not optimal for classes (like containers, strings, etc.) that reuse resources (like previously allocated memory) when x is assigned from a lvalue. +[endsect] + +[section:templated_assignment_operator Templated assignment operator in copyable and movable types] + + +[import ../example/doc_template_assign.cpp] + +Given a movable and copyable class, if a templated assignment operator (*) is added: + +[template_assign_example_foo_bar] + +C++98 and C++11 compilers will behave different when assigning from a `[const] Foo` lvalue: + +[template_assign_example_main] + +This different behaviour is a side-effect of the move emulation that can't be easily avoided by +[*Boost.Move]. One workaround is to SFINAE-out the templated assignment operator with `disable_if`: + +[c++] + + template // Modified templated assignment + typename boost::disable_if, Foo&>::type + operator=(const U& rhs) + { i = -rhs.i; return *this; } //(2) + + [endsect] [endsect] @@ -762,6 +788,14 @@ Many thanks to all boosters that have tested, reviewed and improved the library. [section:release_notes Release Notes] +[section:release_notes_boost_1_62 Boost 1.62 Release] + +* Documented new limitations reported in Trac tickets + [@https://svn.boost.org/trac/boost/ticket/12194 #12194 ['"Copy assignment on moveable and copyable classes uses wrong type"]] and + [@https://svn.boost.org/trac/boost/ticket/12307 #12307 ['"Copy assignment on moveable and copyable classes uses wrong type"]]. + +[endsect] + [section:release_notes_boost_1_61 Boost 1.61 Release] * Experimental: asymptotically optimal bufferless merge and sort algorithms: [funcref boost::movelib::adaptive_merge adaptive_merge] diff --git a/example/doc_template_assign.cpp b/example/doc_template_assign.cpp new file mode 100644 index 0000000..e1959a9 --- /dev/null +++ b/example/doc_template_assign.cpp @@ -0,0 +1,98 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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 + +//[template_assign_example_foo_bar + +class Foo +{ + BOOST_COPYABLE_AND_MOVABLE(Foo) + + public: + int i; + explicit Foo(int val) : i(val) {} + + Foo(BOOST_RV_REF(Foo) obj) : i(obj.i) {} + + Foo& operator=(BOOST_RV_REF(Foo) rhs) + { i = rhs.i; rhs.i = 0; return *this; } + + Foo& operator=(BOOST_COPY_ASSIGN_REF(Foo) rhs) + { i = rhs.i; return *this; } //(1) + + template //(*) TEMPLATED ASSIGNMENT, potential problem + //<- + #if 1 + typename ::boost::move_detail::disable_if_same::type + operator=(const U& rhs) + #else + //-> + Foo& operator=(const U& rhs) + //<- + #endif + //-> + { i = -rhs.i; return *this; } //(2) +}; +//] + +struct Bar +{ + int i; + explicit Bar(int val) : i(val) {} +}; + + +//<- +#ifdef NDEBUG +#undef NDEBUG +#endif +//-> +#include + +int main() +{ +//[template_assign_example_main + Foo foo1(1); + //<- + assert(foo1.i == 1); + //-> + Foo foo2(2); + //<- + assert(foo2.i == 2); + Bar bar(3); + assert(bar.i == 3); + //-> + foo2 = foo1; // Calls (1) in C++11 but (2) in C++98 + //<- + assert(foo2.i == 1); + assert(foo1.i == 1); //Fails in C++98 unless workaround is applied + foo1 = bar; + assert(foo1.i == -3); + foo2 = boost::move(foo1); + assert(foo1.i == 0); + assert(foo2.i == -3); + //-> + const Foo foo5(5); + foo2 = foo5; // Calls (1) in C++11 but (2) in C++98 + //<- + assert(foo2.i == 5); //Fails in C++98 unless workaround is applied + assert(foo5.i == 5); + //-> +//] + return 0; +} + + +#include diff --git a/include/boost/move/detail/meta_utils_core.hpp b/include/boost/move/detail/meta_utils_core.hpp index 4d715a0..40dbb6e 100644 --- a/include/boost/move/detail/meta_utils_core.hpp +++ b/include/boost/move/detail/meta_utils_core.hpp @@ -114,6 +114,18 @@ struct is_same static const bool value = true; }; +////////////////////////////////////// +// enable_if_same +////////////////////////////////////// +template +struct enable_if_same : enable_if, R> {}; + +////////////////////////////////////// +// disable_if_same +////////////////////////////////////// +template +struct disable_if_same : disable_if, R> {}; + } //namespace move_detail { } //namespace boost { diff --git a/proj/vc7ide/Move.sln b/proj/vc7ide/Move.sln index cde7565..e8fabd2 100644 --- a/proj/vc7ide/Move.sln +++ b/proj/vc7ide/Move.sln @@ -127,6 +127,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "adaptive_merge_test", "adap ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_template_assign", "doc_template_assign.vcproj", "{7460CA18-D532-E4F8-F1F2-3A796D2A91E2}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug @@ -263,6 +267,10 @@ Global {CD617A28-6217-B79E-4CE2-6BA035379A6A}.Debug.Build.0 = Debug|Win32 {CD617A28-6217-B79E-4CE2-6BA035379A6A}.Release.ActiveCfg = Release|Win32 {CD617A28-6217-B79E-4CE2-6BA035379A6A}.Release.Build.0 = Release|Win32 + {7460CA18-D532-E4F8-F1F2-3A796D2A91E2}.Debug.ActiveCfg = Debug|Win32 + {7460CA18-D532-E4F8-F1F2-3A796D2A91E2}.Debug.Build.0 = Debug|Win32 + {7460CA18-D532-E4F8-F1F2-3A796D2A91E2}.Release.ActiveCfg = Release|Win32 + {7460CA18-D532-E4F8-F1F2-3A796D2A91E2}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution ..\..\..\..\boost\move\algo\adaptive_merge.hpp = ..\..\..\..\boost\move\algo\adaptive_merge.hpp diff --git a/proj/vc7ide/doc_template_assign.vcproj b/proj/vc7ide/doc_template_assign.vcproj new file mode 100644 index 0000000..c37cb13 --- /dev/null +++ b/proj/vc7ide/doc_template_assign.vcproj @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +