Documented limitations reported in Trac #12194 and Trac #12307

This commit is contained in:
Ion Gaztañaga
2016-07-29 11:55:10 +02:00
parent 1194a39ab3
commit cfd6be4ab4
5 changed files with 286 additions and 0 deletions

View File

@ -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<class U> // Modified templated assignment
typename boost::disable_if<boost::is_same<U, Foo>, 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]

View File

@ -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 <boost/move/detail/config_begin.hpp>
#include <boost/move/detail/meta_utils_core.hpp>
#include <boost/move/move.hpp>
//[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<class U> //(*) TEMPLATED ASSIGNMENT, potential problem
//<-
#if 1
typename ::boost::move_detail::disable_if_same<U, Foo, Foo&>::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 <cassert>
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 <boost/move/detail/config_end.hpp>

View File

@ -114,6 +114,18 @@ struct is_same<T, T>
static const bool value = true;
};
//////////////////////////////////////
// enable_if_same
//////////////////////////////////////
template <class T, class U, class R = void>
struct enable_if_same : enable_if<is_same<T, U>, R> {};
//////////////////////////////////////
// disable_if_same
//////////////////////////////////////
template <class T, class U, class R = void>
struct disable_if_same : disable_if<is_same<T, U>, R> {};
} //namespace move_detail {
} //namespace boost {

View File

@ -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

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="doc_template_assign"
ProjectGUID="{7460CA18-D532-E4F8-F1F2-3A796D2A91E2}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../Bin/Win32/Debug"
IntermediateDirectory="Debug/doc_template_assign"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
DisableLanguageExtensions="FALSE"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/doc_template_assign_d.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/doc_template_assign.pdb"
SubSystem="1"
TargetMachine="1"
FixedBaseAddress="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../Bin/Win32/Release"
IntermediateDirectory="Release/doc_template_assign"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../.."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
RuntimeLibrary="2"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="FALSE"
UsePrecompiledHeader="0"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="winmm.lib"
OutputFile="$(OutDir)/doc_template_assign.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../../stage/lib"
GenerateDebugInformation="TRUE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{475F3C87-6465-7BC5-05A6-2454C0A2A2CF}">
<File
RelativePath="..\..\example\doc_template_assign.cpp">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>