From a3b478b6209b40b1e467b7e6bc5907efb3783a18 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 12 Apr 2014 09:10:24 +0100 Subject: [PATCH 01/18] Use super-project's css file. --- doc/Jamfile.v2 | 2 +- doc/html/boostbook.css | 582 ----------------------------------------- 2 files changed, 1 insertion(+), 583 deletions(-) delete mode 100755 doc/html/boostbook.css diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 93998d0..95de749 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -10,6 +10,7 @@ # Quickbook # ----------------------------------------------------------------------------- +using boostbook ; import quickbook ; path-constant images : html ; @@ -24,7 +25,6 @@ boostbook standalone optional : boost.root=../../../.. - html.stylesheet=boostbook.css toc.max.depth=2 toc.section.depth=2 chunk.section.depth=1 diff --git a/doc/html/boostbook.css b/doc/html/boostbook.css deleted file mode 100755 index e5d7bb5..0000000 --- a/doc/html/boostbook.css +++ /dev/null @@ -1,582 +0,0 @@ -/*============================================================================= - Copyright (c) 2004 Joel de Guzman - http://spirit.sourceforge.net/ - - Use, modification and distribution is subject to 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) -=============================================================================*/ - -/*============================================================================= - Body defaults -=============================================================================*/ - - body - { - margin: 1em; - font-family: sans-serif; - } - -/*============================================================================= - Paragraphs -=============================================================================*/ - - p - { - text-align: left; - font-size: 10pt; - line-height: 1.15; - } - -/*============================================================================= - Program listings -=============================================================================*/ - - /* Code on paragraphs */ - p tt.computeroutput - { - font-size: 10pt; - } - - pre.synopsis - { - font-size: 10pt; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - .programlisting, - .screen - { - font-size: 10pt; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - /* Program listings in tables don't get borders */ - td .programlisting, - td .screen - { - margin: 0pc 0pc 0pc 0pc; - padding: 0pc 0pc 0pc 0pc; - } - -/*============================================================================= - Headings -=============================================================================*/ - - h1, h2, h3, h4, h5, h6 - { - text-align: left; - margin: 1em 0em 0.5em 0em; - font-weight: bold; - } - - h1 { font: 140% } - h2 { font: bold 140% } - h3 { font: bold 130% } - h4 { font: bold 120% } - h5 { font: italic 110% } - h6 { font: italic 100% } - - /* Top page titles */ - title, - h1.title, - h2.title - h3.title, - h4.title, - h5.title, - h6.title, - .refentrytitle - { - font-weight: bold; - margin-bottom: 1pc; - } - - h1.title { font-size: 140% } - h2.title { font-size: 140% } - h3.title { font-size: 130% } - h4.title { font-size: 120% } - h5.title { font-size: 110% } - h6.title { font-size: 100% } - - .section h1 - { - margin: 0em 0em 0.5em 0em; - font-size: 140%; - } - - .section h2 { font-size: 140% } - .section h3 { font-size: 130% } - .section h4 { font-size: 120% } - .section h5 { font-size: 110% } - .section h6 { font-size: 100% } - - /* Code on titles */ - h1 tt.computeroutput { font-size: 140% } - h2 tt.computeroutput { font-size: 140% } - h3 tt.computeroutput { font-size: 130% } - h4 tt.computeroutput { font-size: 120% } - h5 tt.computeroutput { font-size: 110% } - h6 tt.computeroutput { font-size: 100% } - -/*============================================================================= - Author -=============================================================================*/ - - h3.author - { - font-size: 100% - } - -/*============================================================================= - Lists -=============================================================================*/ - - li - { - font-size: 10pt; - line-height: 1.3; - } - - /* Unordered lists */ - ul - { - text-align: left; - } - - /* Ordered lists */ - ol - { - text-align: left; - } - -/*============================================================================= - Links -=============================================================================*/ - - a - { - text-decoration: none; /* no underline */ - } - - a:hover - { - text-decoration: underline; - } - -/*============================================================================= - Spirit style navigation -=============================================================================*/ - - .spirit-nav - { - text-align: right; - } - - .spirit-nav a - { - color: white; - padding-left: 0.5em; - } - - .spirit-nav img - { - border-width: 0px; - } - -/*============================================================================= - Table of contents -=============================================================================*/ - - .toc - { - margin: 1pc 4% 0pc 4%; - padding: 0.1pc 1pc 0.1pc 1pc; - font-size: 10pt; - line-height: 1.15; - } - - .toc-main - { - text-align: center; - margin: 3pc 16% 3pc 16%; - padding: 3pc 1pc 3pc 1pc; - line-height: 0.1; - } - - .boost-toc - { - float: right; - padding: 0.5pc; - } - -/*============================================================================= - Tables -=============================================================================*/ - - .table-title, - div.table p.title - { - margin-left: 4%; - padding-right: 0.5em; - padding-left: 0.5em; - } - - .informaltable table, - .table table - { - width: 92%; - margin-left: 4%; - margin-right: 4%; - } - - div.informaltable table, - div.table table - { - padding: 4px; - } - - /* Table Cells */ - div.informaltable table tr td, - div.table table tr td - { - padding: 0.5em; - text-align: left; - } - - div.informaltable table tr th, - div.table table tr th - { - padding: 0.5em 0.5em 0.5em 0.5em; - border: 1pt solid white; - font-size: 120%; - } - -/*============================================================================= - Blurbs -=============================================================================*/ - - div.note, - div.tip, - div.important, - div.caution, - div.warning, - div.sidebar - { - font-size: 10pt; - line-height: 1.2; - display: block; - margin: 1pc 4% 0pc 4%; - padding: 0.5pc 0.5pc 0.5pc 0.5pc; - } - - div.sidebar img - { - padding: 1pt; - } - - - -/*============================================================================= - Callouts -=============================================================================*/ - .line_callout_bug img - { - float: left; - position:relative; - left: 4px; - top: -12px; - clear: left; - margin-left:-22px; - } - - .callout_bug img - { - } - - - -/*============================================================================= - Variable Lists -=============================================================================*/ - - /* Make the terms in definition lists bold */ - div.variablelist dl dt, - span.term - { - font-weight: bold; - font-size: 10pt; - } - - div.variablelist table tbody tr td - { - text-align: left; - vertical-align: top; - padding: 0em 2em 0em 0em; - font-size: 10pt; - margin: 0em 0em 0.5em 0em; - line-height: 1; - } - - /* Make the terms in definition lists bold */ - div.variablelist dl dt - { - margin-bottom: 0.2em; - } - - div.variablelist dl dd - { - margin: 0em 0em 0.5em 2em; - font-size: 10pt; - } - - div.variablelist table tbody tr td p - div.variablelist dl dd p - { - margin: 0em 0em 0.5em 0em; - line-height: 1; - } - -/*============================================================================= - Misc -=============================================================================*/ - - /* Title of books and articles in bibliographies */ - span.title - { - font-style: italic; - } - - span.underline - { - text-decoration: underline; - } - - span.strikethrough - { - text-decoration: line-through; - } - - /* Copyright, Legal Notice */ - div div.legalnotice p - { - text-align: left - } - -/*============================================================================= - Colors -=============================================================================*/ - - @media screen - { - /* Links */ - a - { - color: #0C7445; - } - - a:visited - { - color: #663974; - } - - h1 a, h2 a, h3 a, h4 a, h5 a, h6 a, - h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover, - h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited - { - text-decoration: none; /* no underline */ - color: #000000; - } - - /* Syntax Highlighting */ - .keyword { color: #0000AA; } - .identifier { color: #000000; } - .special { color: #707070; } - .preprocessor { color: #402080; } - .char { color: teal; } - .comment { color: #800000; } - .string { color: teal; } - .number { color: teal; } - .white_bkd { background-color: #E8FBE9; } - .dk_grey_bkd { background-color: #A0DAAC; } - - /* Copyright, Legal Notice */ - .copyright - { - color: #666666; - font-size: small; - } - - div div.legalnotice p - { - color: #666666; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - .programlisting, - .screen - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - td .programlisting, - td .screen - { - border: 0px solid #DCDCDC; - } - - /* Blurbs */ - div.note, - div.tip, - div.important, - div.caution, - div.warning, - div.sidebar - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - /* Table of contents */ - .toc - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - /* Table of contents */ - .toc-main - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid #DCDCDC; - background-color: #FAFFFB; - } - - div.informaltable table tr th, - div.table table tr th - { - background-color: #E3F9E4; - border: 1px solid #DCDCDC; - } - - /* Misc */ - span.highlight - { - color: #00A000; - } - } - - @media print - { - /* Links */ - a - { - color: black; - } - - a:visited - { - color: black; - } - - .spirit-nav - { - display: none; - } - - /* Program listing */ - pre.synopsis - { - border: 1px solid gray; - background-color: #FAFFFB; - } - - .programlisting, - .screen - { - border: 1px solid gray; - background-color: #FAFFFB; - } - - td .programlisting, - td .screen - { - border: 0px solid #DCDCDC; - } - - /* Table of contents */ - .toc - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - /* Table of contents */ - .toc-main - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - background-color: #FAFFFB; - } - - .informaltable table, - .table table - { - border: 1px solid #DCDCDC; - border-bottom: 3px solid #9D9D9D; - border-right: 3px solid #9D9D9D; - border-collapse: collapse; - background-color: #FAFFFB; - } - - /* Tables */ - div.informaltable table tr td, - div.table table tr td - { - border: 1px solid #DCDCDC; - background-color: #FAFFFB; - } - - div.informaltable table tr th, - div.table table tr th - { - border: 1px solid #DCDCDC; - background-color: #FAFFFB; - } - - /* Misc */ - span.highlight - { - font-weight: bold; - } - } From b4738ac07ecb8644f1de40ea2d07193a4ca50ce1 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 12 Apr 2014 20:54:37 +0200 Subject: [PATCH 02/18] Updated HTML documentation format using the super-project css and docbook-xsl-1.78.1 --- doc/html/HTML.manifest | 14 -------------- .../a_note_about_optional_bool_.html | 4 ++-- doc/html/boost_optional/acknowledgments.html | 4 ++-- .../dependencies_and_portability.html | 4 ++-- doc/html/boost_optional/detailed_semantics.html | 4 ++-- doc/html/boost_optional/development.html | 6 +++--- doc/html/boost_optional/examples.html | 6 +++--- .../exception_safety_guarantees.html | 4 ++-- doc/html/boost_optional/implementation_notes.html | 4 ++-- doc/html/boost_optional/in_place_factories.html | 4 ++-- doc/html/boost_optional/optional_references.html | 4 ++-- ...tics_for_assignment_of_optional_references.html | 4 ++-- doc/html/boost_optional/synopsis.html | 4 ++-- doc/html/boost_optional/type_requirements.html | 4 ++-- doc/html/index.html | 6 +++--- 15 files changed, 31 insertions(+), 45 deletions(-) delete mode 100644 doc/html/HTML.manifest diff --git a/doc/html/HTML.manifest b/doc/html/HTML.manifest deleted file mode 100644 index 759b268..0000000 --- a/doc/html/HTML.manifest +++ /dev/null @@ -1,14 +0,0 @@ -index.html -boost_optional/development.html -boost_optional/synopsis.html -boost_optional/detailed_semantics.html -boost_optional/examples.html -boost_optional/optional_references.html -boost_optional/rebinding_semantics_for_assignment_of_optional_references.html -boost_optional/in_place_factories.html -boost_optional/a_note_about_optional_bool_.html -boost_optional/exception_safety_guarantees.html -boost_optional/type_requirements.html -boost_optional/implementation_notes.html -boost_optional/dependencies_and_portability.html -boost_optional/acknowledgments.html diff --git a/doc/html/boost_optional/a_note_about_optional_bool_.html b/doc/html/boost_optional/a_note_about_optional_bool_.html index 8d70d49..c9f3a78 100644 --- a/doc/html/boost_optional/a_note_about_optional_bool_.html +++ b/doc/html/boost_optional/a_note_about_optional_bool_.html @@ -2,8 +2,8 @@ A note about optional<bool> - - + + diff --git a/doc/html/boost_optional/acknowledgments.html b/doc/html/boost_optional/acknowledgments.html index d56c25c..6ae8176 100644 --- a/doc/html/boost_optional/acknowledgments.html +++ b/doc/html/boost_optional/acknowledgments.html @@ -2,8 +2,8 @@ Acknowledgments - - + + diff --git a/doc/html/boost_optional/dependencies_and_portability.html b/doc/html/boost_optional/dependencies_and_portability.html index 6fa31dd..928f4bd 100644 --- a/doc/html/boost_optional/dependencies_and_portability.html +++ b/doc/html/boost_optional/dependencies_and_portability.html @@ -2,8 +2,8 @@ Dependencies and Portability - - + + diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 9f8b56b..4ab1a29 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -2,8 +2,8 @@ Detailed Semantics - - + + diff --git a/doc/html/boost_optional/development.html b/doc/html/boost_optional/development.html index 7f21580..9cc75e8 100644 --- a/doc/html/boost_optional/development.html +++ b/doc/html/boost_optional/development.html @@ -2,8 +2,8 @@ Development - - + + @@ -26,7 +26,7 @@ -
+
The models
The semantics
The Interface
diff --git a/doc/html/boost_optional/examples.html b/doc/html/boost_optional/examples.html index 54c3953..ad0e02f 100644 --- a/doc/html/boost_optional/examples.html +++ b/doc/html/boost_optional/examples.html @@ -2,8 +2,8 @@ Examples - - + + @@ -26,7 +26,7 @@ -
+
Optional return values
Optional diff --git a/doc/html/boost_optional/exception_safety_guarantees.html b/doc/html/boost_optional/exception_safety_guarantees.html index 4ffa059..09d7766 100644 --- a/doc/html/boost_optional/exception_safety_guarantees.html +++ b/doc/html/boost_optional/exception_safety_guarantees.html @@ -2,8 +2,8 @@ Exception Safety Guarantees - - + + diff --git a/doc/html/boost_optional/implementation_notes.html b/doc/html/boost_optional/implementation_notes.html index fdec333..cfa2fad 100644 --- a/doc/html/boost_optional/implementation_notes.html +++ b/doc/html/boost_optional/implementation_notes.html @@ -2,8 +2,8 @@ Implementation Notes - - + + diff --git a/doc/html/boost_optional/in_place_factories.html b/doc/html/boost_optional/in_place_factories.html index b13dcdf..ec7e39d 100644 --- a/doc/html/boost_optional/in_place_factories.html +++ b/doc/html/boost_optional/in_place_factories.html @@ -2,8 +2,8 @@ In-Place Factories - - + + diff --git a/doc/html/boost_optional/optional_references.html b/doc/html/boost_optional/optional_references.html index c6ad1e1..a603c1c 100644 --- a/doc/html/boost_optional/optional_references.html +++ b/doc/html/boost_optional/optional_references.html @@ -2,8 +2,8 @@ Optional references - - + + diff --git a/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html b/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html index e9b21a4..6dbac4d 100644 --- a/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html +++ b/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html @@ -2,8 +2,8 @@ Rebinding semantics for assignment of optional references - - + + diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html index ca3c1b6..078dd02 100644 --- a/doc/html/boost_optional/synopsis.html +++ b/doc/html/boost_optional/synopsis.html @@ -2,8 +2,8 @@ Synopsis - - + + diff --git a/doc/html/boost_optional/type_requirements.html b/doc/html/boost_optional/type_requirements.html index e148299..9723c4c 100644 --- a/doc/html/boost_optional/type_requirements.html +++ b/doc/html/boost_optional/type_requirements.html @@ -2,8 +2,8 @@ Type requirements - - + + diff --git a/doc/html/index.html b/doc/html/index.html index 12803e7..2103f59 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -2,8 +2,8 @@ Chapter 1. Boost.Optional - - + + @@ -35,7 +35,7 @@

Table of Contents

-
+
Motivation
Development
From 587ef8e9889d4f597890bc78a8debe889b0dd0d3 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 14 Apr 2014 23:44:34 +0200 Subject: [PATCH 03/18] Added 'raw' move semantics; no unit-tests --- include/boost/optional/optional.hpp | 137 ++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 9 deletions(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 603facd..4ae36f0 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -131,6 +131,9 @@ struct types_when_isnt_ref { typedef T const& reference_const_type ; typedef T & reference_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef T && rval_reference_type ; +#endif typedef T const* pointer_const_type ; typedef T * pointer_type ; typedef T const& argument_type ; @@ -140,11 +143,14 @@ struct types_when_is_ref { typedef BOOST_DEDUCED_TYPENAME remove_reference::type raw_type ; - typedef raw_type& reference_const_type ; - typedef raw_type& reference_type ; - typedef raw_type* pointer_const_type ; - typedef raw_type* pointer_type ; - typedef raw_type& argument_type ; + typedef raw_type& reference_const_type ; + typedef raw_type& reference_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef raw_type&& rval_reference_type ; +#endif + typedef raw_type* pointer_const_type ; + typedef raw_type* pointer_type ; + typedef raw_type& argument_type ; } ; struct optional_tag {} ; @@ -184,6 +190,9 @@ class optional_base : public optional_tag typedef BOOST_DEDUCED_TYPENAME types::reference_type reference_type ; typedef BOOST_DEDUCED_TYPENAME types::reference_const_type reference_const_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef BOOST_DEDUCED_TYPENAME types::rval_reference_type rval_reference_type ; +#endif typedef BOOST_DEDUCED_TYPENAME types::pointer_type pointer_type ; typedef BOOST_DEDUCED_TYPENAME types::pointer_const_type pointer_const_type ; typedef BOOST_DEDUCED_TYPENAME types::argument_type argument_type ; @@ -209,6 +218,17 @@ class optional_base : public optional_tag construct(val); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // move-construct an optional initialized from an rvalue-ref to 'val'. + // Can throw if T::T(T&&) does + optional_base ( rval_reference_type val ) + : + m_initialized(false) + { + construct( static_cast(val) ); + } +#endif + // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional. // Can throw if T::T(T const&) does optional_base ( bool cond, argument_type val ) @@ -229,6 +249,17 @@ class optional_base : public optional_tag construct(rhs.get_impl()); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Creates a deep move of another optional + // Can throw if T::T(T&&) does + optional_base ( optional_base&& rhs ) + : + m_initialized(false) + { + if ( rhs.is_initialized() ) + construct( static_cast(rhs.get_impl()) ); + } +#endif // This is used for both converting and in-place constructions. // Derived classes use the 'tag' to select the appropriate @@ -279,6 +310,26 @@ class optional_base : public optional_tag } } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // move-assigns from another _convertible_ optional (deep-moves from the rhs value) + template + void assign ( optional&& rhs ) + { + typedef BOOST_DEDUCED_TYPENAME optional::rval_reference_type ref_type; + if (is_initialized()) + { + if ( rhs.is_initialized() ) + assign_value(static_cast(rhs.get()), is_reference_predicate() ); + else destroy(); + } + else + { + if ( rhs.is_initialized() ) + construct(static_cast(rhs.get())); + } + } +#endif + // Assigns from a T (deep-copies the rhs value) void assign ( argument_type val ) { @@ -286,6 +337,16 @@ class optional_base : public optional_tag assign_value(val, is_reference_predicate() ); else construct(val); } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Assigns from a T (deep-moves the rhs value) + void assign ( rval_reference_type val ) + { + if (is_initialized()) + assign_value( static_cast(val), is_reference_predicate() ); + else construct( static_cast(val) ); + } +#endif // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) @@ -325,6 +386,14 @@ class optional_base : public optional_tag new (m_storage.address()) internal_type(val) ; m_initialized = true ; } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + void construct ( rval_reference_type val ) + { + new (m_storage.address()) internal_type( static_cast(val) ) ; + m_initialized = true ; + } +#endif #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT // Constructs in-place using the given factory @@ -411,6 +480,10 @@ class optional_base : public optional_tag void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } void assign_value ( argument_type val, is_reference_tag ) { construct(val); } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + void assign_value ( rval_reference_type val, is_not_reference_tag ) { get_impl() = static_cast(val); } + void assign_value ( rval_reference_type val, is_reference_tag ) { construct( static_cast(val) ); } +#endif void destroy() { @@ -488,22 +561,34 @@ class optional : public optional_detail::optional_base typedef BOOST_DEDUCED_TYPENAME base::value_type value_type ; typedef BOOST_DEDUCED_TYPENAME base::reference_type reference_type ; typedef BOOST_DEDUCED_TYPENAME base::reference_const_type reference_const_type ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef BOOST_DEDUCED_TYPENAME base::rval_reference_type rval_reference_type ; +#endif typedef BOOST_DEDUCED_TYPENAME base::pointer_type pointer_type ; typedef BOOST_DEDUCED_TYPENAME base::pointer_const_type pointer_const_type ; typedef BOOST_DEDUCED_TYPENAME base::argument_type argument_type ; // Creates an optional uninitialized. // No-throw - optional() : base() {} + optional() BOOST_NOEXCEPT : base() {} // Creates an optional uninitialized. // No-throw - optional( none_t none_ ) : base(none_) {} + optional( none_t none_ ) BOOST_NOEXCEPT : base(none_) {} // Creates an optional initialized with 'val'. // Can throw if T::T(T const&) does optional ( argument_type val ) : base(val) {} +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Creates an optional initialized with 'move(val)'. + // Can throw if T::T(T &&) does + optional ( rval_reference_type val ) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(val)))) + : + base( static_cast(val) ) + {} +#endif + // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. // Can throw if T::T(T const&) does optional ( bool cond, argument_type val ) : base(cond,val) {} @@ -521,6 +606,20 @@ class optional : public optional_detail::optional_base if ( rhs.is_initialized() ) this->construct(rhs.get()); } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Creates a deep move of another convertible optional + // Requires a valid conversion from U to T. + // Can throw if T::T(U&&) does + template + explicit optional ( optional && rhs ) + : + base() + { + if ( rhs.is_initialized() ) + this->construct( static_cast::rval_reference_type>(rhs.get()) ); + } +#endif #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT // Creates an optional with an expression which can be either @@ -573,6 +672,16 @@ class optional : public optional_detail::optional_base return *this ; } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Assigns from another optional (deep-moves the rhs value) + optional& operator= ( optional && rhs ) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*rhs))) && BOOST_NOEXCEPT_EXPR(*rhs = static_cast(*rhs))) + { + this->assign( static_cast(rhs) ) ; + return *this ; + } +#endif + // Assigns from a T (deep-copies the rhs value) // Basic Guarantee: If T::( T const& ) throws, this is left UNINITIALIZED optional& operator= ( argument_type val ) @@ -581,6 +690,15 @@ class optional : public optional_detail::optional_base return *this ; } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Assigns from a T (deep-moves the rhs value) + optional& operator= ( rval_reference_type val ) + { + this->assign( static_cast(val) ) ; + return *this ; + } +#endif + // Assigns from a "none" // Which destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) @@ -591,10 +709,10 @@ class optional : public optional_detail::optional_base } void swap( optional & arg ) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*arg))) && BOOST_NOEXCEPT_EXPR(*arg = static_cast(*arg))) { // allow for Koenig lookup - using boost::swap; - swap(*this, arg); + boost::swap(*this, arg); } @@ -961,6 +1079,7 @@ template struct optional_swap_should_use_default_constructor : has_nothrow_default_constructor {} ; template inline void swap ( optional& x, optional& y ) + BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*x))) && BOOST_NOEXCEPT_EXPR(*y = static_cast(*x))) { optional_detail::swap_selector::value>::optional_swap(x, y); } From a26d11be8767f4e32974cb71fbd8aa071b19beaf Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Tue, 22 Apr 2014 22:36:19 +0200 Subject: [PATCH 04/18] Partially added move semantics (tests are still failing) --- include/boost/optional/optional.hpp | 157 ++++++++++++--- include/boost/optional/optional_fwd.hpp | 10 +- test/Jamfile.v2 | 25 +-- test/optional_test_move.cpp | 254 ++++++++++++++++++++++++ 4 files changed, 404 insertions(+), 42 deletions(-) create mode 100644 test/optional_test_move.cpp diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 4ae36f0..c063e94 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -36,6 +38,8 @@ #include #include #include +#include +#include #include @@ -91,7 +95,8 @@ class in_place_factory_base ; class typed_in_place_factory_base ; // This forward is needed to refer to namespace scope swap from the member swap -template void swap ( optional& x, optional& y ); +template void swap ( optional& x, optional& y ) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value); namespace optional_detail { @@ -225,7 +230,7 @@ class optional_base : public optional_tag : m_initialized(false) { - construct( static_cast(val) ); + construct( boost::move(val) ); } #endif @@ -257,10 +262,21 @@ class optional_base : public optional_tag m_initialized(false) { if ( rhs.is_initialized() ) - construct( static_cast(rhs.get_impl()) ); + construct( boost::move(rhs.get_impl()) ); } #endif +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + template + explicit optional_base ( Expr&& expr, PtrExpr const* tag ) + : + m_initialized(false) + { + construct(boost::forward(expr),tag); + } + +#else // This is used for both converting and in-place constructions. // Derived classes use the 'tag' to select the appropriate // implementation (the correct 'construct()' overload) @@ -272,6 +288,7 @@ class optional_base : public optional_tag construct(expr,tag); } +#endif // No-throw (assuming T::~T() doesn't) @@ -338,13 +355,13 @@ class optional_base : public optional_tag else construct(val); } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Assigns from a T (deep-moves the rhs value) void assign ( rval_reference_type val ) { if (is_initialized()) - assign_value( static_cast(val), is_reference_predicate() ); - else construct( static_cast(val) ); + assign_value( boost::move(val), is_reference_predicate() ); + else construct( boost::move(val) ); } #endif @@ -353,13 +370,25 @@ class optional_base : public optional_tag void assign ( none_t ) { destroy(); } #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + void assign_expr ( Expr&& expr, ExprPtr const* tag ) + { + if (is_initialized()) + assign_expr_to_initialized(boost::forward(expr),tag); + else construct(boost::forward(expr),tag); + } +#else template void assign_expr ( Expr const& expr, Expr const* tag ) - { - if (is_initialized()) - assign_expr_to_initialized(expr,tag); - else construct(expr,tag); - } + { + if (is_initialized()) + assign_expr_to_initialized(expr,tag); + else construct(expr,tag); + } +#endif + #endif public : @@ -390,7 +419,7 @@ class optional_base : public optional_tag #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES void construct ( rval_reference_type val ) { - new (m_storage.address()) internal_type( static_cast(val) ) ; + new (m_storage.address()) internal_type( boost::move(val) ) ; m_initialized = true ; } #endif @@ -430,7 +459,29 @@ class optional_base : public optional_tag } #endif - // Constructs using any expression implicitely convertible to the single argument +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Constructs using any expression implicitly convertible to the single argument + // of a one-argument T constructor. + // Converting constructions of optional from optional uses this function with + // 'Expr' being of type 'U' and relying on a converting constructor of T from U. + template + void construct ( Expr&& expr, void const* ) + { + new (m_storage.address()) internal_type(boost::forward(expr)) ; + m_initialized = true ; + } + + // Assigns using a form any expression implicitly convertible to the single argument + // of a T's assignment operator. + // Converting assignments of optional from optional uses this function with + // 'Expr' being of type 'U' and relying on a converting assignment of T from U. + template + void assign_expr_to_initialized ( Expr&& expr, void const* ) + { + assign_value(boost::forward(expr), is_reference_predicate()); + } +#else + // Constructs using any expression implicitly convertible to the single argument // of a one-argument T constructor. // Converting constructions of optional from optional uses this function with // 'Expr' being of type 'U' and relying on a converting constructor of T from U. @@ -441,7 +492,7 @@ class optional_base : public optional_tag m_initialized = true ; } - // Assigns using a form any expression implicitely convertible to the single argument + // Assigns using a form any expression implicitly convertible to the single argument // of a T's assignment operator. // Converting assignments of optional from optional uses this function with // 'Expr' being of type 'U' and relying on a converting assignment of T from U. @@ -451,6 +502,8 @@ class optional_base : public optional_tag assign_value(expr, is_reference_predicate()); } +#endif + #ifdef BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION // BCB5.64 (and probably lower versions) workaround. // The in-place factories are supported by means of catch-all constructors @@ -583,10 +636,7 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Creates an optional initialized with 'move(val)'. // Can throw if T::T(T &&) does - optional ( rval_reference_type val ) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(val)))) - : - base( static_cast(val) ) - {} + optional ( rval_reference_type val ) : base( boost::forward(val) ) {} #endif // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. @@ -617,7 +667,7 @@ class optional : public optional_detail::optional_base base() { if ( rhs.is_initialized() ) - this->construct( static_cast::rval_reference_type>(rhs.get()) ); + this->construct( boost::move(rhs.get()) ); } #endif @@ -625,32 +675,75 @@ class optional : public optional_detail::optional_base // Creates an optional with an expression which can be either // (a) An instance of InPlaceFactory (i.e. in_place(a,b,...,n); // (b) An instance of TypedInPlaceFactory ( i.e. in_place(a,b,...,n); - // (c) Any expression implicitely convertible to the single type + // (c) Any expression implicitly convertible to the single type // of a one-argument T's constructor. // (d*) Weak compilers (BCB) might also resolved Expr as optional and optional // even though explicit overloads are present for these. // Depending on the above some T ctor is called. - // Can throw is the resolved T ctor throws. + // Can throw if the resolved T ctor throws. +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +#ifndef BOOST_NO_SFINAE +#else + template + explicit optional ( Expr&& expr, typename boost::disable_if::type, optional> >::type* = 0 ) + : base(boost::forward(expr),boost::addressof(expr)) {} +#endif +#else template explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} +#endif #endif // Creates a deep copy of another optional // Can throw if T::T(T const&) does optional ( optional const& rhs ) : base( static_cast(rhs) ) {} +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Creates a deep move of another optional + // Can throw if T::T(T&&) does + optional ( optional && rhs ) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value) + : base( boost::move(rhs) ) + {} + +#ifdef BOOST_NO_SFINAE + // To avoid too perfect forwarding + optional ( optional& rhs ) : base( static_cast(rhs) ) {} +#endif + +#endif // No-throw (assuming T::~T() doesn't) ~optional() {} #if !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) // Assigns from an expression. See corresponding constructor. // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + template +#if !defined BOOST_NO_SFINAE + typename boost::disable_if< + boost::is_same::type, optional>, + optional& + >::type +#else + optional& +#endif + operator= ( Expr&& expr ) + { + this->assign_expr(boost::forward(expr),boost::addressof(expr)); + return *this ; + } + +#else template optional& operator= ( Expr const& expr ) { this->assign_expr(expr,boost::addressof(expr)); return *this ; } +#endif #endif // Assigns from another convertible optional (converts && deep-copies the rhs value) @@ -675,11 +768,19 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Assigns from another optional (deep-moves the rhs value) optional& operator= ( optional && rhs ) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*rhs))) && BOOST_NOEXCEPT_EXPR(*rhs = static_cast(*rhs))) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value) { - this->assign( static_cast(rhs) ) ; + this->assign( static_cast(rhs) ) ; return *this ; } +#ifdef BOOST_NO_SFINAE + // to avoid too perfect forwarding + optional& operator= ( optional& rhs ) + { + this->assign( static_cast(rhs) ) ; + return *this ; + } +#endif #endif // Assigns from a T (deep-copies the rhs value) @@ -694,7 +795,7 @@ class optional : public optional_detail::optional_base // Assigns from a T (deep-moves the rhs value) optional& operator= ( rval_reference_type val ) { - this->assign( static_cast(val) ) ; + this->assign( boost::move(val) ) ; return *this ; } #endif @@ -709,7 +810,7 @@ class optional : public optional_detail::optional_base } void swap( optional & arg ) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*arg))) && BOOST_NOEXCEPT_EXPR(*arg = static_cast(*arg))) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value) { // allow for Koenig lookup boost::swap(*this, arg); @@ -740,11 +841,11 @@ class optional : public optional_detail::optional_base // implicit conversion to "bool" // No-throw - operator unspecified_bool_type() const { return this->safe_bool() ; } + operator unspecified_bool_type() const BOOST_NOEXCEPT { return this->safe_bool() ; } // This is provided for those compilers which don't like the conversion to bool // on some contexts. - bool operator!() const { return !this->is_initialized() ; } + bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; } } ; // Returns optional(v) @@ -1079,7 +1180,7 @@ template struct optional_swap_should_use_default_constructor : has_nothrow_default_constructor {} ; template inline void swap ( optional& x, optional& y ) - BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(static_cast(*x))) && BOOST_NOEXCEPT_EXPR(*y = static_cast(*x))) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value) { optional_detail::swap_selector::value>::optional_swap(x, y); } diff --git a/include/boost/optional/optional_fwd.hpp b/include/boost/optional/optional_fwd.hpp index 388cc1c..ade503d 100644 --- a/include/boost/optional/optional_fwd.hpp +++ b/include/boost/optional/optional_fwd.hpp @@ -11,15 +11,21 @@ // // Revisions: // 10 May 2008 (added swap related forward declaration) Niels Dekker -// +// 17 Apr 2014 (added noexcept) Andrzej Krzemienski +// #ifndef BOOST_OPTIONAL_OPTIONAL_FWD_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FWD_FLC_19NOV2002_HPP +#include +#include +#include + namespace boost { template class optional ; -template void swap ( optional& , optional& ) ; +template void swap ( optional& , optional& ) + BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value); template struct optional_swap_should_use_default_constructor ; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 16d4f3c..62ab883 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -17,17 +17,18 @@ import testing ; { test-suite optional : [ run optional_test.cpp ] - [ run optional_test_tie.cpp ] - [ run optional_test_ref.cpp ] - [ run optional_test_inplace.cpp ] - [ run optional_test_io.cpp ] - [ compile-fail optional_test_fail1.cpp ] - [ compile-fail optional_test_fail3a.cpp ] - [ compile-fail optional_test_fail3b.cpp ] - [ compile-fail optional_test_ref_fail1.cpp ] - [ compile-fail optional_test_ref_fail3.cpp ] - [ compile-fail optional_test_ref_fail4.cpp ] - [ compile-fail optional_test_inplace_fail.cpp ] - [ compile-fail optional_test_inplace_fail2.cpp ] + #[ run optional_test_tie.cpp ] + #[ run optional_test_ref.cpp ] + #[ run optional_test_inplace.cpp ] + #[ run optional_test_io.cpp ] + [ run optional_test_move.cpp ] + #[ compile-fail optional_test_fail1.cpp ] + #[ compile-fail optional_test_fail3a.cpp ] + #[ compile-fail optional_test_fail3b.cpp ] + #[ compile-fail optional_test_ref_fail1.cpp ] + #[ compile-fail optional_test_ref_fail3.cpp ] + #[ compile-fail optional_test_ref_fail4.cpp ] + #[ compile-fail optional_test_inplace_fail.cpp ] + #[ compile-fail optional_test_inplace_fail2.cpp ] ; } diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp new file mode 100644 index 0000000..986ce43 --- /dev/null +++ b/test/optional_test_move.cpp @@ -0,0 +1,254 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +// Revisions: +// +#include +#include +#include + +#define BOOST_ENABLE_ASSERT_HANDLER + +#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin +#include "boost/mpl/bool.hpp" +#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/none.hpp" + +#include "boost/test/minimal.hpp" + +#include "optional_test_common.cpp" + +//#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT +//#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +enum State +{ + sDefaultConstructed, + sValueCopyConstructed, + sValueMoveConstructed, + sCopyConstructed, + sMoveConstructed, + sMoveAssigned, + sCopyAssigned, + sValueCopyAssigned, + sValueMoveAssigned, + sMovedFrom, + sIntConstructed +}; + +struct OracleVal +{ + State s; + int i; + OracleVal(int i = 0) : s(sIntConstructed), i(i) {} +}; + + +struct Oracle +{ + State s; + OracleVal val; + + Oracle() : s(sDefaultConstructed) {} + Oracle(const OracleVal& v) : s(sValueCopyConstructed), val(v) {} + Oracle(OracleVal&& v) : s(sValueMoveConstructed), val(std::move(v)) {v.s = sMovedFrom;} + Oracle(const Oracle& o) : s(sCopyConstructed), val(o.val) {} + Oracle(Oracle&& o) : s(sMoveConstructed), val(std::move(o.val)) {o.s = sMovedFrom;} + + Oracle& operator=(const OracleVal& v) { s = sValueCopyAssigned; val = v; return *this; } + Oracle& operator=(OracleVal&& v) { s = sValueMoveAssigned; val = std::move(v); v.s = sMovedFrom; return *this; } + Oracle& operator=(const Oracle& o) { s = sCopyAssigned; val = o.val; return *this; } + Oracle& operator=(Oracle&& o) { s = sMoveAssigned; val = std::move(o.val); o.s = sMovedFrom; return *this; } +}; + +bool operator==( Oracle const& a, Oracle const& b ) { return a.val.i == b.val.i; } +bool operator!=( Oracle const& a, Oracle const& b ) { return a.val.i != b.val.i; } + + +void test_move_ctor_from_U() +{ + optional o1 ((OracleVal())); + BOOST_CHECK(o1); + BOOST_CHECK(o1->s == sValueMoveConstructed || o1->s == sMoveConstructed); + + OracleVal v1; + optional o2 (v1); + BOOST_CHECK(o2); + std::cout << "AK" << " @@@ " << o2->s << std::endl; + BOOST_CHECK(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed ); + BOOST_CHECK(v1.s == sIntConstructed); + + optional o3 (boost::move(v1)); + BOOST_CHECK(o3); + BOOST_CHECK(o3->s == sValueMoveConstructed || o3->s == sMoveConstructed); + BOOST_CHECK(v1.s == sMovedFrom); +} + +void test_move_ctor_form_T() +{ + optional o1 ((Oracle())); + BOOST_CHECK(o1); + BOOST_CHECK(o1->s == sMoveConstructed); + + Oracle v1; + optional o2 (v1); + BOOST_CHECK(o2); + BOOST_CHECK(o2->s == sCopyConstructed); + BOOST_CHECK(v1.s == sDefaultConstructed); + + optional o3 (boost::move(v1)); + BOOST_CHECK(o3); + BOOST_CHECK(o3->s == sMoveConstructed); + BOOST_CHECK(v1.s == sMovedFrom); +} + +void test_move_ctor_from_optional_T() +{ + optional o1; + optional o2(boost::move(o1)); + + BOOST_CHECK(!o1); + BOOST_CHECK(!o2); + + optional o3((Oracle())); + optional o4(boost::move(o3)); + BOOST_CHECK(o3); + BOOST_CHECK(o4); + BOOST_CHECK(o3->s == sMovedFrom); + BOOST_CHECK(o4->s == sMoveConstructed); + + optional o5((optional())); + BOOST_CHECK(!o5); + + optional o6((optional(Oracle()))); + BOOST_CHECK(o6); + BOOST_CHECK(o6->s == sMoveConstructed); + + optional o7(o6); // does copy ctor from non-const lvalue compile? +} + +void test_move_assign_from_U() +{ + optional o1; + o1 = OracleVal(); + BOOST_CHECK(o1); + + BOOST_CHECK(o1->s == sValueMoveConstructed); + + o1 = OracleVal(); + BOOST_CHECK(o1); + BOOST_CHECK(o1->s == sMoveAssigned); + + OracleVal v1; + optional o2; + o2 = v1; + BOOST_CHECK(o2); + BOOST_CHECK(o2->s == sValueCopyConstructed); + BOOST_CHECK(v1.s == sIntConstructed); + o2 = v1; + BOOST_CHECK(o2); + BOOST_CHECK(o2->s == sCopyAssigned || o2->s == sMoveAssigned); + BOOST_CHECK(v1.s == sIntConstructed); + + optional o3; + o3 = boost::move(v1); + BOOST_CHECK(o3); + BOOST_CHECK(o3->s == sValueMoveConstructed); + BOOST_CHECK(v1.s == sMovedFrom); +} + +void test_move_assign_from_T() +{ + optional o1; + o1 = Oracle(); + BOOST_CHECK(o1); + BOOST_CHECK(o1->s == sMoveConstructed); + + o1 = Oracle(); + BOOST_CHECK(o1); + BOOST_CHECK(o1->s == sMoveAssigned); + + Oracle v1; + optional o2; + o2 = v1; + BOOST_CHECK(o2); + BOOST_CHECK(o2->s == sCopyConstructed); + BOOST_CHECK(v1.s == sDefaultConstructed); + o2 = v1; + BOOST_CHECK(o2); + BOOST_CHECK(o2->s == sCopyAssigned); + BOOST_CHECK(v1.s == sDefaultConstructed); + + optional o3; + o3 = boost::move(v1); + BOOST_CHECK(o3); + BOOST_CHECK(o3->s == sMoveConstructed); + BOOST_CHECK(v1.s == sMovedFrom); +} + +void test_move_ssign_from_optional_T() +{ + optional o1; + optional o2; + o1 = optional(); + BOOST_CHECK(!o1); + optional o3((Oracle())); + o1 = o3; + /*BOOST_CHECK(o3); + BOOST_CHECK(o3->s == sDefaultConstructed); + BOOST_CHECK(o1); + BOOST_CHECK(o1->s == sCopyConstructed); + + o2 = boost::move(o3); + BOOST_CHECK(o3); + BOOST_CHECK(o3->s == sMovedFrom); + BOOST_CHECK(o2); + BOOST_CHECK(o2->s == sMoveConstructed); + + o2 = optional((Oracle())); + BOOST_CHECK(o2); + BOOST_CHECK(o2->s == sMoveAssigned);*/ +} + + +#endif + +int test_main( int, char* [] ) +{ + try + { +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + test_move_ctor_from_U(); + test_move_ctor_form_T(); + test_move_ctor_from_optional_T(); + test_move_assign_from_U(); + test_move_assign_from_T(); + test_move_ssign_from_optional_T(); +#endif + } + catch ( ... ) + { + BOOST_ERROR("Unexpected Exception caught!"); + } + + return 0; +} + + From 5c69bac12fd362242838b7c622c4552903808065 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 26 Apr 2014 00:22:39 +0200 Subject: [PATCH 05/18] Fixed unit tests (still need to add more unit tests for move semantics) --- include/boost/optional/optional.hpp | 75 +++++++++++++++++++---------- test/Jamfile.v2 | 24 ++++----- test/optional_test_move.cpp | 3 +- 3 files changed, 64 insertions(+), 38 deletions(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index c063e94..6933a05 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -27,6 +27,7 @@ #include #include #include + #include #include #include #include @@ -425,6 +426,41 @@ class optional_base : public optional_tag #endif #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Constructs in-place using the given factory + template + void construct ( Expr&& factory, in_place_factory_base const* ) + { + BOOST_STATIC_ASSERT ( ::boost::mpl::not_::value ) ; + boost_optional_detail::construct(factory, m_storage.address()); + m_initialized = true ; + } + + // Constructs in-place using the given typed factory + template + void construct ( Expr&& factory, typed_in_place_factory_base const* ) + { + BOOST_STATIC_ASSERT ( ::boost::mpl::not_::value ) ; + factory.apply(m_storage.address()) ; + m_initialized = true ; + } + + template + void assign_expr_to_initialized ( Expr&& factory, in_place_factory_base const* tag ) + { + destroy(); + construct(factory,tag); + } + + // Constructs in-place using the given typed factory + template + void assign_expr_to_initialized ( Expr&& factory, typed_in_place_factory_base const* tag ) + { + destroy(); + construct(factory,tag); + } +#else // Constructs in-place using the given factory template void construct ( Expr const& factory, in_place_factory_base const* ) @@ -459,6 +495,8 @@ class optional_base : public optional_tag } #endif +#endif + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Constructs using any expression implicitly convertible to the single argument // of a one-argument T constructor. @@ -683,12 +721,16 @@ class optional : public optional_detail::optional_base // Can throw if the resolved T ctor throws. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES -#ifndef BOOST_NO_SFINAE -#else + template - explicit optional ( Expr&& expr, typename boost::disable_if::type, optional> >::type* = 0 ) + explicit optional ( Expr&& expr, + typename boost::disable_if_c< + (boost::is_base_of::type>::value) || + boost::is_same::type, optional>::value || + boost::is_same::type, none_t>::value >::type* = 0 + ) : base(boost::forward(expr),boost::addressof(expr)) {} -#endif + #else template explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} @@ -707,11 +749,6 @@ class optional : public optional_detail::optional_base : base( boost::move(rhs) ) {} -#ifdef BOOST_NO_SFINAE - // To avoid too perfect forwarding - optional ( optional& rhs ) : base( static_cast(rhs) ) {} -#endif - #endif // No-throw (assuming T::~T() doesn't) ~optional() {} @@ -722,14 +759,10 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template -#if !defined BOOST_NO_SFINAE - typename boost::disable_if< - boost::is_same::type, optional>, + typename boost::disable_if_c< + boost::is_base_of::type>::value || boost::is_same::type, optional>::value || boost::is_same::type, none_t>::value, optional& >::type -#else - optional& -#endif operator= ( Expr&& expr ) { this->assign_expr(boost::forward(expr),boost::addressof(expr)); @@ -743,8 +776,8 @@ class optional : public optional_detail::optional_base this->assign_expr(expr,boost::addressof(expr)); return *this ; } -#endif -#endif +#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) // Assigns from another convertible optional (converts && deep-copies the rhs value) // Requires a valid conversion from U to T. @@ -773,14 +806,6 @@ class optional : public optional_detail::optional_base this->assign( static_cast(rhs) ) ; return *this ; } -#ifdef BOOST_NO_SFINAE - // to avoid too perfect forwarding - optional& operator= ( optional& rhs ) - { - this->assign( static_cast(rhs) ) ; - return *this ; - } -#endif #endif // Assigns from a T (deep-copies the rhs value) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 62ab883..a146f72 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -17,18 +17,18 @@ import testing ; { test-suite optional : [ run optional_test.cpp ] - #[ run optional_test_tie.cpp ] - #[ run optional_test_ref.cpp ] - #[ run optional_test_inplace.cpp ] - #[ run optional_test_io.cpp ] + [ run optional_test_tie.cpp ] + [ run optional_test_ref.cpp ] + [ run optional_test_inplace.cpp ] + [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] - #[ compile-fail optional_test_fail1.cpp ] - #[ compile-fail optional_test_fail3a.cpp ] - #[ compile-fail optional_test_fail3b.cpp ] - #[ compile-fail optional_test_ref_fail1.cpp ] - #[ compile-fail optional_test_ref_fail3.cpp ] - #[ compile-fail optional_test_ref_fail4.cpp ] - #[ compile-fail optional_test_inplace_fail.cpp ] - #[ compile-fail optional_test_inplace_fail2.cpp ] + [ compile-fail optional_test_fail1.cpp ] + [ compile-fail optional_test_fail3a.cpp ] + [ compile-fail optional_test_fail3b.cpp ] + [ compile-fail optional_test_ref_fail1.cpp ] + [ compile-fail optional_test_ref_fail3.cpp ] + [ compile-fail optional_test_ref_fail4.cpp ] + [ compile-fail optional_test_inplace_fail.cpp ] + [ compile-fail optional_test_inplace_fail2.cpp ] ; } diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp index 986ce43..0f52c2d 100644 --- a/test/optional_test_move.cpp +++ b/test/optional_test_move.cpp @@ -146,7 +146,8 @@ void test_move_ctor_from_optional_T() void test_move_assign_from_U() { - optional o1; + optional o1 = boost::none; // test if additional ctors didn't break it + o1 = boost::none; // test if additional assignments didn't break it o1 = OracleVal(); BOOST_CHECK(o1); From c7cf80e5df873e11dab3f6bf01c897c9bb661d7b Mon Sep 17 00:00:00 2001 From: Marcel Raad Date: Thu, 24 Apr 2014 10:00:43 +0200 Subject: [PATCH 06/18] Use BOOST_EXPLICIT_OPERATOR_BOOL for optional I often have the problem that when I change a std::wstring to boost::optional and the variable is used as a parameter with Boost.Format, the result silently changes from the string contents to "1". This change prevents implicit conversion to bool if the compiler supports explicit conversion operators. --- .../boost_optional/detailed_semantics.html | 9 ++++-- doc/html/boost_optional/synopsis.html | 2 +- doc/html/index.html | 2 +- doc/reference.qbk | 8 +++--- include/boost/optional/optional.hpp | 15 ++-------- test/Jamfile.v2 | 1 + test/optional_test.cpp | 4 +-- ...tional_test_fail_implicit_bool_convert.cpp | 28 +++++++++++++++++++ 8 files changed, 46 insertions(+), 23 deletions(-) create mode 100644 test/optional_test_fail_implicit_bool_convert.cpp diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 4ab1a29..9163af0 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -981,16 +981,19 @@ space

- optional<T>::operator unspecified-bool-type() const ; + explicit optional<T>::operator bool() const ;

  • - Returns: An unspecified value which if - used on a boolean context is equivalent to (get_ptr() != 0) + Returns: get_ptr() != 0.
  • Throws: Nothing.
  • +
  • + Notes: On compilers that do not support + explicit conversion operators this falls back to safe-bool idiom. +
  • Example:
    optional<T> def ;
    diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html
    index 078dd02..802fa02 100644
    --- a/doc/html/boost_optional/synopsis.html
    +++ b/doc/html/boost_optional/synopsis.html
    @@ -81,7 +81,7 @@
         T const* get_ptr() const ; R
         T*       get_ptr() ; R
     
    -    operator unspecified-bool-type() const ; R
    +    explicit operator bool() const ; R
     
         bool operator!() const ; R
     
    diff --git a/doc/html/index.html b/doc/html/index.html
    index 2103f59..bdc5e5d 100644
    --- a/doc/html/index.html
    +++ b/doc/html/index.html
    @@ -163,7 +163,7 @@
     
- +

Last revised: April 11, 2014 at 13:25:26 GMT

Last revised: April 26, 2014 at 08:58:33 GMT


diff --git a/doc/reference.qbk b/doc/reference.qbk index cd0234c..d7cdfed 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -66,7 +66,7 @@ T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]`` T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]`` - operator unspecified-bool-type() const ; ``[link reference_optional_operator_bool __GO_TO__]`` + explicit operator bool() const ; ``[link reference_optional_operator_bool __GO_TO__]`` bool operator!() const ; ``[link reference_optional_operator_not __GO_TO__]`` @@ -657,11 +657,11 @@ __SPACE__ [#reference_optional_operator_bool] -[: `optional::operator `['unspecified-bool-type]`() const ;`] +[: `explicit optional::operator bool() const ;`] -* [*Returns:] An unspecified value which if used on a boolean context -is equivalent to (`get_ptr() != 0`) +* [*Returns:] `get_ptr() != 0`. * [*Throws:] Nothing. +* [*Notes:] On compilers that do not support explicit conversion operators this falls back to safe-bool idiom. * [*Example:] `` optional def ; diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 603facd..d87b6fa 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -180,8 +181,6 @@ class optional_base : public optional_tag typedef BOOST_DEDUCED_TYPENAME mpl::if_::type types ; protected: - typedef bool (this_type::*unspecified_bool_type)() const; - typedef BOOST_DEDUCED_TYPENAME types::reference_type reference_type ; typedef BOOST_DEDUCED_TYPENAME types::reference_const_type reference_const_type ; typedef BOOST_DEDUCED_TYPENAME types::pointer_type pointer_type ; @@ -418,8 +417,6 @@ class optional_base : public optional_tag destroy_impl(is_reference_predicate()) ; } - unspecified_bool_type safe_bool() const { return m_initialized ? &this_type::is_initialized : 0 ; } - reference_const_type get_impl() const { return dereference(get_object(), is_reference_predicate() ) ; } reference_type get_impl() { return dereference(get_object(), is_reference_predicate() ) ; } @@ -479,8 +476,6 @@ class optional : public optional_detail::optional_base { typedef optional_detail::optional_base base ; - typedef BOOST_DEDUCED_TYPENAME base::unspecified_bool_type unspecified_bool_type ; - public : typedef optional this_type ; @@ -620,13 +615,9 @@ class optional : public optional_detail::optional_base reference_const_type operator *() const { return this->get() ; } reference_type operator *() { return this->get() ; } - // implicit conversion to "bool" - // No-throw - operator unspecified_bool_type() const { return this->safe_bool() ; } - - // This is provided for those compilers which don't like the conversion to bool - // on some contexts. bool operator!() const { return !this->is_initialized() ; } + + BOOST_EXPLICIT_OPERATOR_BOOL() } ; // Returns optional(v) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 16d4f3c..290bb1b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -29,5 +29,6 @@ import testing ; [ compile-fail optional_test_ref_fail4.cpp ] [ compile-fail optional_test_inplace_fail.cpp ] [ compile-fail optional_test_inplace_fail2.cpp ] + [ compile-fail optional_test_fail_implicit_bool_convert.cpp ] ; } diff --git a/test/optional_test.cpp b/test/optional_test.cpp index c3f9355..ba64269 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -1086,8 +1086,8 @@ namespace optional_swap_test // void swap(boost::optional & x, boost::optional & y) { - bool hasX = x; - bool hasY = y; + bool hasX(x); + bool hasY(y); if ( !hasX && !hasY ) return; diff --git a/test/optional_test_fail_implicit_bool_convert.cpp b/test/optional_test_fail_implicit_bool_convert.cpp new file mode 100644 index 0000000..5009373 --- /dev/null +++ b/test/optional_test_fail_implicit_bool_convert.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2014, Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" + +// +// THIS TEST SHOULD FAIL TO COMPILE +// + +#if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + +bool test_implicit_conversion_to_bool() +{ + boost::optional opt; + return opt; +} + +#else +# error "Test skipped: this compiler does not support explicit conversion operators." +#endif From 0e61751fab82a177a6deab511e1fb5f150e12534 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 26 Apr 2014 23:24:21 +0200 Subject: [PATCH 07/18] Added more tests for move operations, fixed bugs, disabled optional. --- include/boost/optional/optional.hpp | 38 ++++++-- test/Jamfile.v2 | 2 + ...onal_test_fail_copying_a_moveable_type.cpp | 36 ++++++++ ...optional_test_fail_optional_rvalue_ref.cpp | 19 ++++ test/optional_test_move.cpp | 86 +++++++++++++++++-- 5 files changed, 170 insertions(+), 11 deletions(-) create mode 100644 test/optional_test_fail_copying_a_moveable_type.cpp create mode 100644 test/optional_test_fail_optional_rvalue_ref.cpp diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 6933a05..053486e 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -21,13 +21,14 @@ #include #include +#include #include #include #include #include #include #include - #include +#include #include #include #include @@ -139,6 +140,7 @@ struct types_when_isnt_ref typedef T & reference_type ; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES typedef T && rval_reference_type ; + static rval_reference_type move(reference_type r) { return boost::move(r); } #endif typedef T const* pointer_const_type ; typedef T * pointer_type ; @@ -153,6 +155,7 @@ struct types_when_is_ref typedef raw_type& reference_type ; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES typedef raw_type&& rval_reference_type ; + static reference_type move(reference_type r) { return r; } #endif typedef raw_type* pointer_const_type ; typedef raw_type* pointer_type ; @@ -310,6 +313,24 @@ class optional_base : public optional_tag construct(rhs.get_impl()); } } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Assigns from another optional (deep-moves the rhs value) + void assign ( optional_base&& rhs ) + { + if (is_initialized()) + { + if ( rhs.is_initialized() ) + assign_value(boost::move(rhs.get_impl()), is_reference_predicate() ); + else destroy(); + } + else + { + if ( rhs.is_initialized() ) + construct(boost::move(rhs.get_impl())); + } + } +#endif // Assigns from another _convertible_ optional (deep-copies the rhs value) template @@ -328,7 +349,7 @@ class optional_base : public optional_tag } } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // move-assigns from another _convertible_ optional (deep-moves from the rhs value) template void assign ( optional&& rhs ) @@ -420,7 +441,7 @@ class optional_base : public optional_tag #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES void construct ( rval_reference_type val ) { - new (m_storage.address()) internal_type( boost::move(val) ) ; + new (m_storage.address()) internal_type( types::move(val) ) ; m_initialized = true ; } #endif @@ -726,7 +747,6 @@ class optional : public optional_detail::optional_base explicit optional ( Expr&& expr, typename boost::disable_if_c< (boost::is_base_of::type>::value) || - boost::is_same::type, optional>::value || boost::is_same::type, none_t>::value >::type* = 0 ) : base(boost::forward(expr),boost::addressof(expr)) {} @@ -760,7 +780,7 @@ class optional : public optional_detail::optional_base template typename boost::disable_if_c< - boost::is_base_of::type>::value || boost::is_same::type, optional>::value || boost::is_same::type, none_t>::value, + boost::is_base_of::type>::value || boost::is_same::type, none_t>::value, optional& >::type operator= ( Expr&& expr ) @@ -873,6 +893,14 @@ class optional : public optional_detail::optional_base bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; } } ; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template +class optional +{ + BOOST_STATIC_ASSERT_MSG(sizeof(T) == 0, "Optional rvalue references are illegal."); +} ; +#endif + // Returns optional(v) template inline diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a146f72..e7e53fa 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -30,5 +30,7 @@ import testing ; [ compile-fail optional_test_ref_fail4.cpp ] [ compile-fail optional_test_inplace_fail.cpp ] [ compile-fail optional_test_inplace_fail2.cpp ] + [ compile-fail optional_test_fail_copying_a_moveable_type.cpp ] + [ compile-fail optional_test_fail_optional_rvalue_ref.cpp ] ; } diff --git a/test/optional_test_fail_copying_a_moveable_type.cpp b/test/optional_test_fail_copying_a_moveable_type.cpp new file mode 100644 index 0000000..c1194cd --- /dev/null +++ b/test/optional_test_fail_copying_a_moveable_type.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2014, Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" + +class MoveOnly +{ +public: + int val; + MoveOnly(int v) : val(v) {} + MoveOnly(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; } + void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; } + +private: + MoveOnly(MoveOnly const&); + void operator=(MoveOnly const&); +}; + +// +// THIS TEST SHOULD FAIL TO COMPILE +// +void test_copying_optional_with_noncopyable_T() +{ + boost::optional opt1 ; + boost::optional opt2(opt1) ; +} + + diff --git a/test/optional_test_fail_optional_rvalue_ref.cpp b/test/optional_test_fail_optional_rvalue_ref.cpp new file mode 100644 index 0000000..5a1e039 --- /dev/null +++ b/test/optional_test_fail_optional_rvalue_ref.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2014, Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" +// +// THIS TEST SHOULD FAIL TO COMPILE +// + +boost::optional oi; + + diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp index 0f52c2d..cad5866 100644 --- a/test/optional_test_move.cpp +++ b/test/optional_test_move.cpp @@ -20,6 +20,7 @@ #include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin #include "boost/mpl/bool.hpp" #include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ +#include "boost/static_assert.hpp" #include "boost/optional/optional.hpp" @@ -91,7 +92,6 @@ void test_move_ctor_from_U() OracleVal v1; optional o2 (v1); BOOST_CHECK(o2); - std::cout << "AK" << " @@@ " << o2->s << std::endl; BOOST_CHECK(o2->s == sValueCopyConstructed || o2->s == sCopyConstructed || o2->s == sMoveConstructed ); BOOST_CHECK(v1.s == sIntConstructed); @@ -204,7 +204,7 @@ void test_move_assign_from_T() BOOST_CHECK(v1.s == sMovedFrom); } -void test_move_ssign_from_optional_T() +void test_move_assign_from_optional_T() { optional o1; optional o2; @@ -212,8 +212,8 @@ void test_move_ssign_from_optional_T() BOOST_CHECK(!o1); optional o3((Oracle())); o1 = o3; - /*BOOST_CHECK(o3); - BOOST_CHECK(o3->s == sDefaultConstructed); + BOOST_CHECK(o3); + BOOST_CHECK(o3->s == sMoveConstructed); BOOST_CHECK(o1); BOOST_CHECK(o1->s == sCopyConstructed); @@ -225,9 +225,82 @@ void test_move_ssign_from_optional_T() o2 = optional((Oracle())); BOOST_CHECK(o2); - BOOST_CHECK(o2->s == sMoveAssigned);*/ + BOOST_CHECK(o2->s == sMoveAssigned); } +class MoveOnly +{ +public: + int val; + MoveOnly(int v) : val(v) {} + MoveOnly(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; } + void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; } + +private: + MoveOnly(MoveOnly const&); + void operator=(MoveOnly const&); +}; + +void test_with_move_only() +{ + optional o1; + optional o2((MoveOnly(1))); + BOOST_CHECK(o2); + BOOST_CHECK(o2->val == 1); + optional o3 (boost::move(o1)); + BOOST_CHECK(!o3); + optional o4 (boost::move(o2)); + BOOST_CHECK(o4); + BOOST_CHECK(o4->val == 1); + BOOST_CHECK(o2); + BOOST_CHECK(o2->val == 0); + + o3 = boost::move(o4); + BOOST_CHECK(o3); + BOOST_CHECK(o3->val == 1); + BOOST_CHECK(o4); + BOOST_CHECK(o4->val == 0); +} + +// these 4 classes have different noexcept signatures in move operations +struct NothrowBoth { + NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; + void operator=(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; +}; +struct NothrowCtor { + NothrowCtor(NothrowCtor&&) BOOST_NOEXCEPT_IF(true) {}; + void operator=(NothrowCtor&&) BOOST_NOEXCEPT_IF(false) {}; +}; +struct NothrowAssign { + NothrowAssign(NothrowAssign&&) BOOST_NOEXCEPT_IF(false) {}; + void operator=(NothrowAssign&&) BOOST_NOEXCEPT_IF(true) {}; +}; +struct NothrowNone { + NothrowNone(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {}; + void operator=(NothrowNone&&) BOOST_NOEXCEPT_IF(false) {}; +}; + +#ifndef BOOST_NO_NOEXCEPT + +void test_noexcept() // this is a compile-time test +{ + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); + + BOOST_STATIC_ASSERT(::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); + + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); + + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_constructible >::value); + BOOST_STATIC_ASSERT(!::boost::is_nothrow_move_assignable >::value); + BOOST_STATIC_ASSERT(BOOST_NOEXCEPT_EXPR(optional())); +} +#endif // !defned BOOST_NO_NOEXCEPT #endif @@ -241,7 +314,8 @@ int test_main( int, char* [] ) test_move_ctor_from_optional_T(); test_move_assign_from_U(); test_move_assign_from_T(); - test_move_ssign_from_optional_T(); + test_move_assign_from_optional_T(); + test_with_move_only(); #endif } catch ( ... ) From 381614364688b975329b9f4debb2bb0b131ce6fe Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 28 Apr 2014 15:48:55 +0200 Subject: [PATCH 08/18] Disabled assignment and construction from rvalue references in optional --- include/boost/optional/optional.hpp | 39 +++++++++++++------ test/Jamfile.v2 | 4 ++ ...onal_test_ref_fail_assign_from_Trefref.cpp | 26 +++++++++++++ ...onal_test_ref_fail_assign_from_Urefref.cpp | 26 +++++++++++++ ...tional_test_ref_fail_init_from_Trefref.cpp | 25 ++++++++++++ ...tional_test_ref_fail_init_from_Urefref.cpp | 25 ++++++++++++ 6 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 test/optional_test_ref_fail_assign_from_Trefref.cpp create mode 100644 test/optional_test_ref_fail_assign_from_Urefref.cpp create mode 100644 test/optional_test_ref_fail_init_from_Trefref.cpp create mode 100644 test/optional_test_ref_fail_init_from_Urefref.cpp diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 053486e..a8ba5e6 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -146,6 +148,7 @@ struct types_when_isnt_ref typedef T * pointer_type ; typedef T const& argument_type ; } ; + template struct types_when_is_ref { @@ -162,6 +165,14 @@ struct types_when_is_ref typedef raw_type& argument_type ; } ; +template +void prevent_binding_rvalue_ref_to_optional_lvalue_ref() +{ + BOOST_STATIC_ASSERT_MSG( + !boost::is_lvalue_reference::value || !boost::is_rvalue_reference::value, + "binding rvalue references to optional lvalue references is disallowed"); +} + struct optional_tag {} ; template @@ -272,7 +283,7 @@ class optional_base : public optional_tag #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - template + template explicit optional_base ( Expr&& expr, PtrExpr const* tag ) : m_initialized(false) @@ -695,7 +706,8 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Creates an optional initialized with 'move(val)'. // Can throw if T::T(T &&) does - optional ( rval_reference_type val ) : base( boost::forward(val) ) {} + optional ( rval_reference_type val ) : base( boost::forward(val) ) + {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref();} #endif // Creates an optional initialized with 'val' IFF cond is true, otherwise creates an uninitialized optional. @@ -740,22 +752,23 @@ class optional : public optional_detail::optional_base // even though explicit overloads are present for these. // Depending on the above some T ctor is called. // Can throw if the resolved T ctor throws. -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template explicit optional ( Expr&& expr, - typename boost::disable_if_c< - (boost::is_base_of::type>::value) || - boost::is_same::type, none_t>::value >::type* = 0 + BOOST_DEDUCED_TYPENAME boost::disable_if_c< + (boost::is_base_of::type>::value) || + boost::is_same::type, none_t>::value >::type* = 0 ) - : base(boost::forward(expr),boost::addressof(expr)) {} + : base(boost::forward(expr),boost::addressof(expr)) + {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref();} #else template explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {} -#endif -#endif +#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // !defined BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT // Creates a deep copy of another optional // Can throw if T::T(T const&) does @@ -779,12 +792,14 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template - typename boost::disable_if_c< - boost::is_base_of::type>::value || boost::is_same::type, none_t>::value, + BOOST_DEDUCED_TYPENAME boost::disable_if_c< + boost::is_base_of::type>::value || + boost::is_same::type, none_t>::value, optional& >::type operator= ( Expr&& expr ) { + optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref(); this->assign_expr(boost::forward(expr),boost::addressof(expr)); return *this ; } @@ -836,7 +851,7 @@ class optional : public optional_detail::optional_base return *this ; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES // Assigns from a T (deep-moves the rhs value) optional& operator= ( rval_reference_type val ) { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e7e53fa..ac8017e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -32,5 +32,9 @@ import testing ; [ compile-fail optional_test_inplace_fail2.cpp ] [ compile-fail optional_test_fail_copying_a_moveable_type.cpp ] [ compile-fail optional_test_fail_optional_rvalue_ref.cpp ] + [ compile-fail optional_test_ref_fail_init_from_Trefref.cpp ] + [ compile-fail optional_test_ref_fail_init_from_Urefref.cpp ] + [ compile-fail optional_test_ref_fail_assign_from_Trefref.cpp ] + [ compile-fail optional_test_ref_fail_assign_from_Urefref.cpp ] ; } diff --git a/test/optional_test_ref_fail_assign_from_Trefref.cpp b/test/optional_test_ref_fail_assign_from_Trefref.cpp new file mode 100644 index 0000000..4eb748a --- /dev/null +++ b/test/optional_test_ref_fail_assign_from_Trefref.cpp @@ -0,0 +1,26 @@ +// Copyright (C) 2014, andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +// +// THIS TEST SHOULD FAIL TO COMPILE +// +void optional_reference__test_no_assign_from_Trefref() +{ + boost::optional opt; + opt = int(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif diff --git a/test/optional_test_ref_fail_assign_from_Urefref.cpp b/test/optional_test_ref_fail_assign_from_Urefref.cpp new file mode 100644 index 0000000..b06185f --- /dev/null +++ b/test/optional_test_ref_fail_assign_from_Urefref.cpp @@ -0,0 +1,26 @@ +// Copyright (C) 2014, andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +// +// THIS TEST SHOULD FAIL TO COMPILE +// +void optional_reference__test_no_assign_from_Urefref() +{ + boost::optional opt; + opt = long(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif diff --git a/test/optional_test_ref_fail_init_from_Trefref.cpp b/test/optional_test_ref_fail_init_from_Trefref.cpp new file mode 100644 index 0000000..05752b8 --- /dev/null +++ b/test/optional_test_ref_fail_init_from_Trefref.cpp @@ -0,0 +1,25 @@ +// Copyright (C) 2014, andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +// +// THIS TEST SHOULD FAIL TO COMPILE +// +void optional_reference__test_no_init_from_Trefref() +{ + boost::optional opt = int(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif diff --git a/test/optional_test_ref_fail_init_from_Urefref.cpp b/test/optional_test_ref_fail_init_from_Urefref.cpp new file mode 100644 index 0000000..e15192b --- /dev/null +++ b/test/optional_test_ref_fail_init_from_Urefref.cpp @@ -0,0 +1,25 @@ +// Copyright (C) 2014, andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +#include "boost/optional.hpp" + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +// +// THIS TEST SHOULD FAIL TO COMPILE +// +void optional_reference__test_no_init_from_Urefref() +{ + boost::optional opt = long(3); +} + +#else +# error "Test skipped. This cannot be implemented w/o rvalue references." +#endif From 655a9e3035e8031829ce328b8e8424ed1bbf5c15 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 28 Apr 2014 16:01:55 +0200 Subject: [PATCH 09/18] Added README.md file --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..4f73388 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +optional +======== + +A library for representing optional (nullable) objects in C++. + +```cpp +optional readInt(); // this function may return either an int or a not-an-int + +if (optional oi = readInt()) // did I get a real int + cout << "my int is: " << *oi; // use my int +else + cout << "I have no int"; +``` + +For more information refer to the documentation provided with this library. From 01b22a0ff0f0c68dee34989555fdf857bf1ef2ca Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 28 Apr 2014 16:51:49 +0200 Subject: [PATCH 10/18] Added tests for move conversion between optional and optional --- include/boost/optional/optional.hpp | 29 +++++++++++++++- test/optional_test_move.cpp | 54 +++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index a8ba5e6..bbbe3be 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -587,6 +587,20 @@ class optional_base : public optional_tag // For VC<=70 compilers this workaround dosen't work becasue the comnpiler issues and error // instead of choosing the wrong overload // +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Notice that 'Expr' will be optional or optional (but not optional_base<..>) + template + void construct ( Expr&& expr, optional_tag const* ) + { + if ( expr.is_initialized() ) + { + // An exception can be thrown here. + // It it happens, THIS will be left uninitialized. + new (m_storage.address()) internal_type(types::move(expr.get())) ; + m_initialized = true ; + } + } +#else // Notice that 'Expr' will be optional or optional (but not optional_base<..>) template void construct ( Expr const& expr, optional_tag const* ) @@ -600,6 +614,7 @@ class optional_base : public optional_tag } } #endif +#endif // defined BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION void assign_value ( argument_type val, is_not_reference_tag ) { get_impl() = val; } void assign_value ( argument_type val, is_reference_tag ) { construct(val); } @@ -814,7 +829,7 @@ class optional : public optional_detail::optional_base #endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES #endif // !defined(BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT) && !defined(BOOST_OPTIONAL_WEAK_OVERLOAD_RESOLUTION) - // Assigns from another convertible optional (converts && deep-copies the rhs value) + // Copy-assigns from another convertible optional (converts && deep-copies the rhs value) // Requires a valid conversion from U to T. // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED template @@ -823,6 +838,18 @@ class optional : public optional_detail::optional_base this->assign(rhs); return *this ; } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Move-assigns from another convertible optional (converts && deep-moves the rhs value) + // Requires a valid conversion from U to T. + // Basic Guarantee: If T::T( U && ) throws, this is left UNINITIALIZED + template + optional& operator= ( optional && rhs ) + { + this->assign(boost::move(rhs)); + return *this ; + } +#endif // Assigns from another optional (deep-copies the rhs value) // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp index cad5866..a2d20c1 100644 --- a/test/optional_test_move.cpp +++ b/test/optional_test_move.cpp @@ -239,6 +239,8 @@ public: private: MoveOnly(MoveOnly const&); void operator=(MoveOnly const&); + + friend class MoveOnlyB; }; void test_with_move_only() @@ -262,6 +264,56 @@ void test_with_move_only() BOOST_CHECK(o4->val == 0); } +class MoveOnlyB +{ +public: + int val; + MoveOnlyB(int v) : val(v) {} + MoveOnlyB(MoveOnlyB&& rhs) : val(rhs.val) { rhs.val = 0; } + void operator=(MoveOnlyB&& rhs) {val = rhs.val; rhs.val = 0; } + MoveOnlyB(MoveOnly&& rhs) : val(rhs.val) { rhs.val = 0; } + void operator=(MoveOnly&& rhs) {val = rhs.val; rhs.val = 0; } + +private: + MoveOnlyB(MoveOnlyB const&); + void operator=(MoveOnlyB const&); + MoveOnlyB(MoveOnly const&); + void operator=(MoveOnly const&); +}; + +void test_move_assign_from_optional_U() +{ + optional a((MoveOnly(2))); + optional b1; + b1 = boost::move(a); + + BOOST_CHECK(b1); + BOOST_CHECK(b1->val == 2); + BOOST_CHECK(a); + BOOST_CHECK(a->val == 0); + + b1 = MoveOnly(4); + + BOOST_CHECK(b1); + BOOST_CHECK(b1->val == 4); +} + +void test_move_ctor_from_optional_U() +{ + optional a((MoveOnly(2))); + optional b1(boost::move(a)); + + BOOST_CHECK(b1); + BOOST_CHECK(b1->val == 2); + BOOST_CHECK(a); + BOOST_CHECK(a->val == 0); + + optional b2(( optional(( MoveOnly(4) )) )); + + BOOST_CHECK(b2); + BOOST_CHECK(b2->val == 4); +} + // these 4 classes have different noexcept signatures in move operations struct NothrowBoth { NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; @@ -312,9 +364,11 @@ int test_main( int, char* [] ) test_move_ctor_from_U(); test_move_ctor_form_T(); test_move_ctor_from_optional_T(); + test_move_ctor_from_optional_U(); test_move_assign_from_U(); test_move_assign_from_T(); test_move_assign_from_optional_T(); + test_move_assign_from_optional_U(); test_with_move_only(); #endif } From c9f1422560485545e91e1f7efa32775dcb1a7506 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Tue, 29 Apr 2014 01:06:14 +0200 Subject: [PATCH 11/18] Updated documentation; fixed optional::swap --- .../boost_optional/detailed_semantics.html | 436 +++++++++++++++++- .../boost_optional/optional_references.html | 16 + doc/html/boost_optional/synopsis.html | 18 +- doc/html/index.html | 2 +- doc/reference.qbk | 265 ++++++++++- doc/special_cases.qbk | 7 + include/boost/optional/optional.hpp | 39 +- include/boost/optional/optional_fwd.hpp | 5 +- test/optional_test_move.cpp | 31 ++ 9 files changed, 767 insertions(+), 52 deletions(-) diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 4ab1a29..6fc4760 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -72,7 +72,7 @@ space

- optional<T>::optional(); + optional<T>::optional() noexcept;

  • @@ -82,11 +82,7 @@ Postconditions: *this is uninitialized.
  • - Throws: Nothing. -
  • -
  • - Notes: T's default constructor is not - called. + Notes: T's default constructor is not called.
  • Example: @@ -99,7 +95,7 @@ space

    - optional<T>::optional( none_t ); + optional<T>::optional( none_t ) noexcept;

    • @@ -109,9 +105,6 @@
    • Postconditions: *this is uninitialized.
    • -
    • - Throws: Nothing. -
    • Notes: T's default constructor is not called. @@ -132,12 +125,16 @@ optional<T (not a ref)>::optional( T const& v )

      +
    • + Requires: is_copy_constructible<T>::value + is true. +
    • Effect: Directly-Constructs an optional.
    • Postconditions: *this is initialized - and its value is acopy of v. + and its value is a copy of v.
    • Throws: Whatever T::T( @@ -193,6 +190,58 @@
    +

    + space +

    +

    + optional<T (not a ref)>::optional( T&& + v ) +

    +
      +
    • + Requires: is_move_constructible<T>::value + is true. +
    • +
    • + Effect: Directly-Move-Constructs an optional. +
    • +
    • + Postconditions: *this is initialized + and its value is move-constructed from v. +
    • +
    • + Throws: Whatever T::T( + T&& + ) throws. +
    • +
    • + Notes: T::T( + T&& + ) is called. +
    • +
    • + Exception Safety: Exceptions can only + be thrown during T::T( T&& ); + in that case, the state of v + is determined by exception safety guarantees for T::T(T&&). +
    • +
    • + Example: +
      T v1, v2;
      +optional<T> opt(std::move(v1));
      +assert ( *opt == v2 ) ;
      +
      +
    • +
    +

    + space +

    +

    + optional<T&>::optional( T&& ref ) = delete +

    +
    • + Notes: This constructor is deleted +

    space

    @@ -229,6 +278,10 @@ optional<T (not a ref)>::optional( optional const& rhs );

    +
  • + Requires: is_copy_constructible<T>::value + is true. +
  • Effect: Copy-Constructs an optional.
  • @@ -320,6 +373,116 @@
+

+ space +

+

+ optional<T (not a ref)>::optional( optional&& rhs + ) noexcept(see below); +

+
    +
  • + Requires: is_move_constructible<T>::value + is true. +
  • +
  • + Effect: Move-constructs an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is move constructed from rhs; + else *this + is uninitialized. +
  • +
  • + Throws: Whatever T::T( + T&& + ) throws. +
  • +
  • + Notes: If rhs + is initialized, T::T( T + && ) + is called. The expression inside noexcept + is equivalent to is_nothrow_move_constructible<T>::value. +
  • +
  • + Exception Safety: Exceptions can only + be thrown during T::T( T&& ); + in that case, rhs remains + initialized and the value of *rhs is determined by exception safety + of T::T(T&&). +
  • +
  • + Example: +
    optional<std::unique_ptr<T>> uninit ;
    +assert (!uninit);
    +
    +optional<std::unique_ptr<T>> uinit2 ( std::move(uninit) ) ;
    +assert ( uninit2 == uninit );
    +
    +optional<std::unique_ptr<T>> init( std::uniqye_ptr<T>(new T(2)) );
    +assert ( **init == T(2) ) ;
    +
    +optional<std::unique_ptr<T>> init2 ( std::move(init) ) ;
    +assert ( init );
    +assert ( *init == nullptr );
    +assert ( init2 );
    +assert ( **init2 == T(2) ) ;
    +
    +
  • +
+

+ space +

+

+ optional<T&>::optional( optional && + rhs ); +

+
    +
  • + Effect: Move-Constructs an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is another reference to the same object referenced + by *rhs; + else *this + is uninitialized. +
  • +
  • + Throws: Nothing. +
  • +
  • + Notes: If rhs + is initialized, both *this + and *rhs + will reefer to the same object (they alias). +
  • +
  • + Example: +
    optional<std::unique_ptr<T>&> uninit ;
    +assert (!uninit);
    +
    +optional<std::unique_ptr<T>&> uinit2 ( std::move(uninit) ) ;
    +assert ( uninit2 == uninit );
    +
    +std::unique_ptr<T> v(new T(2)) ;
    +optional<std::unique_ptr<T>&> init(v);
    +assert ( *init == v ) ;
    +
    +optional<std::unique_ptr<T>&> init2 ( std::move(init) ) ;
    +assert ( *init2 == v ) ;
    +
    +*v = 3 ;
    +
    +assert ( **init  == 3 ) ;
    +assert ( **init2 == 3 ) ;
    +
    +
  • +

space

@@ -368,6 +531,52 @@
+

+ space +

+

+ template<U> explicit optional<T + (not a ref)>::optional( optional<U>&& + rhs ); +

+
    +
  • + Effect: Move-constructs an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is move constructed from *rhs; else *this is uninitialized. +
  • +
  • + Throws: Whatever T::T( + U&& + ) throws. +
  • +
  • + Notes: T::T( + U&& + ) is called if rhs + is initialized, which requires a valid conversion from U + to T. +
  • +
  • + Exception Safety: Exceptions can only + be thrown during T::T( U&& ); + in that case, rhs remains + initialized and the value of *rhs is determined by exception safety + guarantee of T::T( U&& ). +
  • +
  • + Example: +
    optional<double> x(123.4);
    +assert ( *x == 123.4 ) ;
    +
    +optional<int> y(std::move(x)) ;
    +assert( *y == 123 ) ;
    +
    +
  • +

space

@@ -511,6 +720,66 @@
+

+ space +

+

+ optional& + optional<T (not a ref)>::operator= ( T&& rhs + ) ; +

+
    +
  • + Effect: Moves the value rhs to an optional. +
  • +
  • + Postconditions: *this is initialized and its value is moved + from rhs. +
  • +
  • + Throws: Whatever T::operator=( T&& ) + or T::T(T + &&) throws. +
  • +
  • + Notes: If *this was initialized, T's + move-assignment operator is used, otherwise, its move-constructor is used. +
  • +
  • + Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned + (it is up to T's operator=()). + If *this + is initially uninitialized and T's + move constructor fails, *this is left properly uninitialized. +
  • +
  • + Example: +
    T x;
    +optional<T> def ;
    +optional<T> opt(x) ;
    +
    +T y1, y2, yR;
    +def = std::move(y1) ;
    +assert ( *def == yR ) ;
    +opt = std::move(y2) ;
    +assert ( *opt == yR ) ;
    +
    +
  • +
+

+ space +

+

+ optional<T&>& + optional<T&>::operator= ( T&& + rhs ) + = delete; +

+
  • + Notes: This assignment operator is deleted. +

space

@@ -613,6 +882,75 @@ +

+ space +

+

+ optional& + optional<T (not a ref)>::operator= ( optional&& rhs + ) noexcept(see below); +

+
    +
  • + Effect: Move-assigns another optional to an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is moved from *rhs, rhs + remains initialized; else *this is uninitialized. +
  • +
  • + Throws: Whatever T::operator( T&& + ) or T::T( + T && + ) throws. +
  • +
  • + Notes: If both *this and rhs + are initially initialized, T's + move assignment operator is used. If *this is + initially initialized but rhs + is uninitialized, T's [destructor] + is called. If *this + is initially uninitialized but rhs + is initialized, T's move + constructor is called. The expression inside noexcept + is equivalent to is_nothrow_move_constructible<T>::value + && is_nothrow_move_assignable<T>::value. +
  • +
  • + Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned (it is up to T's + operator=()). + If *this + is initially uninitialized and T's + move constructor fails, *this is left properly uninitialized. +
  • +
  • + Example: +
    optional<T> opt(T(2)) ;
    +optional<T> def ;
    +
    +opt = def ;
    +assert ( def ) ;
    +assert ( opt ) ;
    +assert ( *opt == T(2) ) ;
    +
    +
  • +
+

+ space +

+

+ optional<T&> & optional<T&>::operator= ( optional<T&>&& + rhs ) + ; +

+
  • + Effect: Same as optional<T&>::operator= ( optional<T&> const& rhs ). +

space

@@ -673,6 +1011,59 @@ +

+ space +

+

+ template<U> optional& + optional<T (not a ref)>::operator= ( optional<U>&& + rhs ) + ; +

+
    +
  • + Effect: Move-assigns another convertible + optional to an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is moved from the value of rhs; + else *this + is uninitialized. +
  • +
  • + Throws: Whatever T::operator=( U&& ) + or T::T( U&& ) + throws. +
  • +
  • + Notes: If both *this and rhs + are initially initialized, T's + assignment operator (from U&&) is used. If *this is initially initialized but rhs is uninitialized, T's + destructor is called. If *this is initially uninitialized but rhs is initialized, T's + converting constructor (from U&&) is called. +
  • +
  • + Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned (it is up to T's + operator=()). + If *this + is initially uninitialized and T's + converting constructor fails, *this is left properly uninitialized. +
  • +
  • + Example: +
    T v;
    +optional<T> opt0(v);
    +optional<U> opt1;
    +
    +opt1 = std::move(opt0) ;
    +assert ( *opt1 == static_cast<U>(v) ) ;
    +
    +
  • +

space

@@ -768,7 +1159,7 @@

  • - Requirements: *this is initialized + Requires: *this is initialized
  • Returns: A reference to the contained @@ -870,7 +1261,7 @@

  • - Requirements: *this is initialized + Requires: *this is initialized
  • Returns: The @@ -956,7 +1347,7 @@

  • - Requirements: *this is initialized. + Requires: *this is initialized.
  • Returns: A pointer to the contained value. @@ -1005,16 +1396,13 @@ space

    - bool optional<T>::operator!() ; + bool optional<T>::operator!() noexcept ;

    • Returns: If *this is uninitialized, true; else false.
    • -
    • - Throws: Nothing. -
    • Notes: This operator is provided for those compilers which can't use the unspecified-bool-type operator @@ -1288,7 +1676,7 @@

      void swap ( optional<T>& - x, optional<T>& y ); + x, optional<T>& y ) ;

      • @@ -1305,19 +1693,21 @@
      • Throws: If both are initialized, whatever swap(T&,T&) - throws. If only one is initialized, whatever T::T ( T const& ) throws. + throws. If only one is initialized, whatever T::T ( T&& + ) throws.
      • Notes: If both are initialized, swap(T&,T&) is used unqualified but with std::swap introduced in scope. If only one is initialized, T::~T() and T::T( - T const& ) - is called. + T&& + ) is called.
      • Exception Safety: If both are initialized, this operation has the exception safety guarantees of swap(T&,T&). - If only one is initialized, it has the same basic guarantee as optional<T>::reset( T const& ). + If only one is initialized, it has the same basic guarantee as optional<T>::operator= ( T&& + ).
      • Example: diff --git a/doc/html/boost_optional/optional_references.html b/doc/html/boost_optional/optional_references.html index a603c1c..92770cf 100644 --- a/doc/html/boost_optional/optional_references.html +++ b/doc/html/boost_optional/optional_references.html @@ -68,6 +68,22 @@ than the reference itself.
      +

      + + Rvalue + references +

      +

      + Rvalue references and lvalue references to const have the ability in C++ to + extend the life time of a temporary they bind to. Optional references do not + have this capability, therefore to avoid surprising effects it is not possible + to initialize an optional references from a temporary. Optional rvalue references + are disabled altogether. Also, the initialization and assignment of an optional + reference to const from rvalue reference is disabled. +

      +
      const int& i = 1;            // legal
      +optional<const int&> oi = 1; // illegal
      +
    diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html index 078dd02..1da981f 100644 --- a/doc/html/boost_optional/synopsis.html +++ b/doc/html/boost_optional/synopsis.html @@ -37,19 +37,25 @@ // (If T is of reference type, the parameters and results by reference are by value) - optional();R + optional()noexcept;R - optional(none_t);R + optional(none_t)noexcept;Roptional(Tconst&v);R + optional(T&&v);R + // [new in 1.34]optional(boolcondition,Tconst&v);Roptional(optionalconst&rhs);R + optional(optional&&rhs)noexcept(see below);R + template<classU>explicitoptional(optional<U>const&rhs);R + template<classU>explicitoptional(optional<U>&&rhs);R + template<classInPlaceFactory>explicitoptional(InPlaceFactoryconst&f);Rtemplate<classTypedInPlaceFactory>explicitoptional(TypedInPlaceFactoryconst&f);R @@ -58,10 +64,16 @@ optional&operator=(Tconst&v);R + optional&operator=(T&&v);R + optional&operator=(optionalconst&rhs);R + optional&operator=(optional&&rhs)noexcept(see below);R + template<classU>optional&operator=(optional<U>const&rhs);R + template<classU>optional&operator=(optional<U>&&rhs);R + template<classInPlaceFactory>optional&operator=(InPlaceFactoryconst&f);Rtemplate<classTypedInPlaceFactory>optional&operator=(TypedInPlaceFactoryconst&f);R @@ -83,7 +95,7 @@ operatorunspecified-bool-type()const;R - booloperator!()const;R + booloperator!()constnoexcept;R// deprecated methods diff --git a/doc/html/index.html b/doc/html/index.html index 2103f59..e1230c1 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -163,7 +163,7 @@
    - +

    Last revised: April 11, 2014 at 13:25:26 GMT

    Last revised: April 28, 2014 at 23:02:29 GMT


    diff --git a/doc/reference.qbk b/doc/reference.qbk index cd0234c..d07c440 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -22,18 +22,24 @@ // (If T is of reference type, the parameters and results by reference are by value) - optional () ; ``[link reference_optional_constructor __GO_TO__]`` + optional () noexcept ; ``[link reference_optional_constructor __GO_TO__]`` - optional ( none_t ) ; ``[link reference_optional_constructor_none_t __GO_TO__]`` + optional ( none_t ) noexcept ; ``[link reference_optional_constructor_none_t __GO_TO__]`` optional ( T const& v ) ; ``[link reference_optional_constructor_value __GO_TO__]`` + + optional ( T&& v ) ; ``[link reference_optional_constructor_move_value __GO_TO__]`` // [new in 1.34] optional ( bool condition, T const& v ) ; ``[link reference_optional_constructor_bool_value __GO_TO__]`` optional ( optional const& rhs ) ; ``[link reference_optional_constructor_optional __GO_TO__]`` + + optional ( optional&& rhs ) noexcept(``['see below]``) ; ``[link reference_optional_move_constructor_optional __GO_TO__]`` template explicit optional ( optional const& rhs ) ; ``[link reference_optional_constructor_other_optional __GO_TO__]`` + + template explicit optional ( optional&& rhs ) ; ``[link reference_optional_move_constructor_other_optional __GO_TO__]`` template explicit optional ( InPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]`` @@ -42,10 +48,16 @@ optional& operator = ( none_t ) ; ``[/[link reference_optional_operator_equal_none_t __GO_TO__]]`` optional& operator = ( T const& v ) ; ``[link reference_optional_operator_equal_value __GO_TO__]`` + + optional& operator = ( T&& v ) ; ``[link reference_optional_operator_move_equal_value __GO_TO__]`` optional& operator = ( optional const& rhs ) ; ``[link reference_optional_operator_equal_optional __GO_TO__]`` + + optional& operator = ( optional&& rhs ) noexcept(``['see below]``) ; ``[link reference_optional_operator_move_equal_optional __GO_TO__]`` template optional& operator = ( optional const& rhs ) ; ``[link reference_optional_operator_equal_other_optional __GO_TO__]`` + + template optional& operator = ( optional&& rhs ) ; ``[link reference_optional_operator_move_equal_other_optional __GO_TO__]`` template optional& operator = ( InPlaceFactory const& f ) ; ``[link reference_optional_operator_equal_factory __GO_TO__]`` @@ -68,7 +80,7 @@ operator unspecified-bool-type() const ; ``[link reference_optional_operator_bool __GO_TO__]`` - bool operator!() const ; ``[link reference_optional_operator_not __GO_TO__]`` + bool operator!() const noexcept ; ``[link reference_optional_operator_not __GO_TO__]`` // deprecated methods @@ -151,12 +163,11 @@ __SPACE__ [#reference_optional_constructor] -[: `optional::optional();`] +[: `optional::optional() noexcept;`] * [*Effect:] Default-Constructs an `optional`. * [*Postconditions:] `*this` is [_uninitialized]. -* [*Throws:] Nothing. -* Notes: T's default constructor [_is not] called. +* [*Notes:] T's default constructor [_is not] called. * [*Example:] `` optional def ; @@ -167,11 +178,10 @@ __SPACE__ [#reference_optional_constructor_none_t] -[: `optional::optional( none_t );`] +[: `optional::optional( none_t ) noexcept;`] * [*Effect:] Constructs an `optional` uninitialized. * [*Postconditions:] `*this` is [_uninitialized]. -* [*Throws:] Nothing. * [*Notes:] `T`'s default constructor [_is not] called. The expression `boost::none` denotes an instance of `boost::none_t` that can be used as the parameter. @@ -188,8 +198,9 @@ __SPACE__ [: `optional::optional( T const& v )`] +* [*Requires:] `is_copy_constructible::value` is `true`. * [*Effect:] Directly-Constructs an `optional`. -* [*Postconditions:] `*this` is [_initialized] and its value is a['copy] +* [*Postconditions:] `*this` is [_initialized] and its value is a ['copy] of `v`. * [*Throws:] Whatever `T::T( T const& )` throws. * [*Notes: ] `T::T( T const& )` is called. @@ -220,6 +231,33 @@ assert ( *opt == v ) ; assert (*opt == v); `` +__SPACE__ + +[#reference_optional_constructor_move_value] + +[: `optional::optional( T&& v )`] + +* [*Requires:] `is_move_constructible::value` is `true`. +* [*Effect:] Directly-Move-Constructs an `optional`. +* [*Postconditions:] `*this` is [_initialized] and its value is move-constructed from `v`. +* [*Throws:] Whatever `T::T( T&& )` throws. +* [*Notes: ] `T::T( T&& )` is called. +* [*Exception Safety:] Exceptions can only be thrown during +`T::T( T&& );` in that case, the state of `v` is determined by exception safety guarantees for `T::T(T&&)`. +* [*Example:] +`` +T v1, v2; +optional opt(std::move(v1)); +assert ( *opt == v2 ) ; +`` + +__SPACE__ + +[: `optional::optional( T&& ref ) = delete`] + +* [*Notes:] This constructor is deleted + + __SPACE__ [#reference_optional_constructor_bool_value] @@ -243,6 +281,7 @@ __SPACE__ [: `optional::optional( optional const& rhs );`] +* [*Requires:] `is_copy_constructible::value` is `true`. * [*Effect:] Copy-Constructs an `optional`. * [*Postconditions:] If rhs is initialized, `*this` is initialized and its value is a ['copy] of the value of `rhs`; else `*this` is uninitialized. @@ -299,6 +338,70 @@ assert ( *init2 == 3 ) ; __SPACE__ +[#reference_optional_move_constructor_optional] + +[: `optional::optional( optional&& rhs ) noexcept(`['see below]`);`] + +* [*Requires:] `is_move_constructible::value` is `true`. +* [*Effect:] Move-constructs an `optional`. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and +its value is move constructed from `rhs`; else `*this` is uninitialized. +* [*Throws:] Whatever `T::T( T&& )` throws. +* [*Notes:] If `rhs` is initialized, `T::T( T && )` is called. The expression inside `noexcept` is equivalent to `is_nothrow_move_constructible::value`. +* [*Exception Safety:] Exceptions can only be thrown during +`T::T( T&& );` in that case, `rhs` remains initialized and the value of `*rhs` is determined by exception safety of `T::T(T&&)`. +* [*Example:] +`` +optional> uninit ; +assert (!uninit); + +optional> uinit2 ( std::move(uninit) ) ; +assert ( uninit2 == uninit ); + +optional> init( std::uniqye_ptr(new T(2)) ); +assert ( **init == T(2) ) ; + +optional> init2 ( std::move(init) ) ; +assert ( init ); +assert ( *init == nullptr ); +assert ( init2 ); +assert ( **init2 == T(2) ) ; +`` + +__SPACE__ + +[: `optional::optional( optional && rhs );`] + +* [*Effect:] Move-Constructs an `optional`. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its +value is another reference to the same object referenced by `*rhs`; else +`*this` is uninitialized. +* [*Throws:] Nothing. +* [*Notes:] If `rhs` is initialized, both `*this` and `*rhs` will reefer to the +same object (they alias). +* [*Example:] +`` +optional&> uninit ; +assert (!uninit); + +optional&> uinit2 ( std::move(uninit) ) ; +assert ( uninit2 == uninit ); + +std::unique_ptr v(new T(2)) ; +optional&> init(v); +assert ( *init == v ) ; + +optional&> init2 ( std::move(init) ) ; +assert ( *init2 == v ) ; + +*v = 3 ; + +assert ( **init == 3 ) ; +assert ( **init2 == 3 ) ; +`` + +__SPACE__ + [#reference_optional_constructor_other_optional] [: `template explicit optional::optional( optional const& rhs );`] @@ -323,6 +426,30 @@ assert( *y == 123 ) ; __SPACE__ +[#reference_optional_move_constructor_other_optional] + +[: `template explicit optional::optional( optional&& rhs );`] + +* [*Effect:] Move-constructs an `optional`. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its +value is move constructed from `*rhs`; else `*this` is +uninitialized. +* [*Throws:] Whatever `T::T( U&& )` throws. +* [*Notes: ] `T::T( U&& )` is called if `rhs` is initialized, which requires a +valid conversion from `U` to `T`. +* [*Exception Safety:] Exceptions can only be thrown during `T::T( U&& );` +in that case, `rhs` remains initialized and the value of `*rhs` is determined by exception safety guarantee of `T::T( U&& )`. +* [*Example:] +`` +optional x(123.4); +assert ( *x == 123.4 ) ; + +optional y(std::move(x)) ; +assert( *y == 123 ) ; +`` + +__SPACE__ + [#reference_optional_constructor_factory] [: `template explicit optional::optional( InPlaceFactory const& f );`] @@ -408,6 +535,42 @@ c = 4 ; assert ( *opt == 4 ) ; `` +__SPACE__ + +[#reference_optional_operator_move_equal_value] + +[: `optional& optional::operator= ( T&& rhs ) ;`] + +* [*Effect:] Moves the value `rhs` to an `optional`. +* [*Postconditions: ] `*this` is initialized and its value is moved from `rhs`. +* [*Throws:] Whatever `T::operator=( T&& )` or `T::T(T &&)` throws. +* [*Notes:] If `*this` was initialized, `T`'s move-assignment operator is used, +otherwise, its move-constructor is used. +* [*Exception Safety:] In the event of an exception, the initialization +state of `*this` is unchanged and its value unspecified as far as `optional` +is concerned (it is up to `T`'s `operator=()`). If `*this` is initially +uninitialized and `T`'s ['move constructor] fails, `*this` is left properly +uninitialized. +* [*Example:] +`` +T x; +optional def ; +optional opt(x) ; + +T y1, y2, yR; +def = std::move(y1) ; +assert ( *def == yR ) ; +opt = std::move(y2) ; +assert ( *opt == yR ) ; +`` + +__SPACE__ + +[: `optional& optional::operator= ( T&& rhs ) = delete;`] + +* [*Notes:] This assignment operator is deleted. + + __SPACE__ [#reference_optional_operator_equal_optional] @@ -471,6 +634,42 @@ assert ( *ora == 4 ) ; __SPACE__ +[#reference_optional_operator_move_equal_optional] + +[: `optional& optional::operator= ( optional&& rhs ) noexcept(`['see below]`);`] + +* [*Effect:] Move-assigns another `optional` to an `optional`. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and +its value is moved from `*rhs`, `rhs` remains initialized; else `*this` is uninitialized. +* [*Throws:] Whatever `T::operator( T&& )` or `T::T( T && )` throws. +* [*Notes:] If both `*this` and `rhs` are initially initialized, `T`'s +['move assignment operator] is used. If `*this` is initially initialized but `rhs` is +uninitialized, `T`'s [destructor] is called. If `*this` is initially uninitialized +but `rhs` is initialized, `T`'s ['move constructor] is called. The expression inside `noexcept` is equivalent to `is_nothrow_move_constructible::value && is_nothrow_move_assignable::value`. +* [*Exception Safety:] In the event of an exception, the initialization state of +`*this` is unchanged and its value unspecified as far as optional is concerned +(it is up to `T`'s `operator=()`). If `*this` is initially uninitialized and +`T`'s ['move constructor] fails, `*this` is left properly uninitialized. +* [*Example:] +`` +optional opt(T(2)) ; +optional def ; + +opt = def ; +assert ( def ) ; +assert ( opt ) ; +assert ( *opt == T(2) ) ; +`` + +__SPACE__ + +[: `optional & optional::operator= ( optional&& rhs ) ;`] + +* [*Effect:] Same as `optional::operator= ( optional const& rhs )`. + +__SPACE__ + + [#reference_optional_operator_equal_other_optional] [: `template optional& optional::operator= ( optional const& rhs ) ;`] @@ -502,6 +701,37 @@ assert ( *opt1 == static_cast(v) ) ; __SPACE__ +[#reference_optional_operator_move_equal_other_optional] + +[: `template optional& optional::operator= ( optional&& rhs ) ;`] + +* [*Effect:] Move-assigns another convertible optional to an optional. +* [*Postconditions:] If `rhs` is initialized, `*this` is initialized and +its value is moved from the value of `rhs`; else +`*this` is uninitialized. +* [*Throws:] Whatever `T::operator=( U&& )` or `T::T( U&& )` throws. +* [*Notes:] If both `*this` and `rhs` are initially initialized, `T`'s +[' assignment operator] (from `U&&`) is used. If `*this` is initially initialized +but `rhs` is uninitialized, `T`'s ['destructor] is called. If `*this` is +initially uninitialized but `rhs` is initialized, `T`'s ['converting constructor] +(from `U&&`) is called. +* [*Exception Safety:] In the event of an exception, the initialization state +of `*this` is unchanged and its value unspecified as far as optional is +concerned (it is up to `T`'s `operator=()`). If `*this` is initially +uninitialized and `T`'s converting constructor fails, `*this` is left properly +uninitialized. +* [*Example:] +`` +T v; +optional opt0(v); +optional opt1; + +opt1 = std::move(opt0) ; +assert ( *opt1 == static_cast(v) ) ; +`` + +__SPACE__ + [#reference_optional_operator_equal_factory] [: `template optional& optional::operator=( InPlaceFactory const& f );`] @@ -543,7 +773,7 @@ __SPACE__ [: `inline T const& get ( optional const& ) ;`] [: `inline T& get ( optional &) ;`] -* [*Requirements:] `*this` is initialized +* [*Requires:] `*this` is initialized * [*Returns:] A reference to the contained value * [*Throws:] Nothing. * [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. @@ -593,7 +823,7 @@ __SPACE__ [: `inline T const& get ( optional const& ) ;`] [: `inline T& get ( optional &) ;`] -* [*Requirements: ] `*this` is initialized +* [*Requires: ] `*this` is initialized * [*Returns:] [_The] reference contained. * [*Throws:] Nothing. * [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. @@ -641,7 +871,7 @@ __SPACE__ [: `T const* optional::operator ->() const ;`] [: `T* optional::operator ->() ;`] -* [*Requirements: ] `*this` is initialized. +* [*Requires: ] `*this` is initialized. * [*Returns:] A pointer to the contained value. * [*Throws:] Nothing. * [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. @@ -675,10 +905,9 @@ __SPACE__ [#reference_optional_operator_not] -[: `bool optional::operator!() ;`] +[: `bool optional::operator!() noexcept ;`] * [*Returns:] If `*this` is uninitialized, `true`; else `false`. -* [*Throws:] Nothing. * [*Notes:] This operator is provided for those compilers which can't use the ['unspecified-bool-type operator] in certain boolean contexts. * [*Example:] @@ -852,21 +1081,21 @@ __SPACE__ [#reference_swap_optional_optional] -[: `void swap ( optional& x, optional& y );`] +[: `void swap ( optional& x, optional& y ) ;`] * [*Effect:] If both `x` and `y` are initialized, calls `swap(*x,*y)` using `std::swap`. If only one is initialized, say `x`, calls: `y.reset(*x); x.reset();` If none is initialized, does nothing. * [*Postconditions:] The states of `x` and `y` interchanged. * [*Throws:] If both are initialized, whatever `swap(T&,T&)` throws. If only -one is initialized, whatever `T::T ( T const& )` throws. +one is initialized, whatever `T::T ( T&& )` throws. * [*Notes:] If both are initialized, `swap(T&,T&)` is used unqualified but with `std::swap` introduced in scope. -If only one is initialized, `T::~T()` and `T::T( T const& )` is called. +If only one is initialized, `T::~T()` and `T::T( T&& )` is called. * [*Exception Safety:] If both are initialized, this operation has the exception safety guarantees of `swap(T&,T&)`. If only one is initialized, it has the same basic guarantee as -`optional::reset( T const& )`. +`optional::operator= ( T&& )`. * [*Example:] `` T x(12); diff --git a/doc/special_cases.qbk b/doc/special_cases.qbk index 681e517..0f6f22b 100644 --- a/doc/special_cases.qbk +++ b/doc/special_cases.qbk @@ -21,6 +21,13 @@ will nonetheless reefer to the same object. * Value-access will actually provide access to the referenced object rather than the reference itself. +[heading Rvalue references] + +Rvalue references and lvalue references to const have the ability in C++ to extend the life time of a temporary they bind to. Optional references do not have this capability, therefore to avoid surprising effects it is not possible to initialize an optional references from a temporary. Optional rvalue references are disabled altogether. Also, the initialization and assignment of an optional reference to const from rvalue reference is disabled. + + const int& i = 1; // legal + optional oi = 1; // illegal + [endsect] [section Rebinding semantics for assignment of optional references] diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index bbbe3be..d191462 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include #include @@ -99,8 +101,7 @@ class in_place_factory_base ; class typed_in_place_factory_base ; // This forward is needed to refer to namespace scope swap from the member swap -template void swap ( optional& x, optional& y ) - BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value); +template void swap ( optional& x, optional& y ); namespace optional_detail { @@ -1242,6 +1243,37 @@ struct swap_selector } }; +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template<> +struct swap_selector +{ + template + static void optional_swap ( optional& x, optional& y ) + //BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && BOOST_NOEXCEPT_EXPR(boost::swap(*x, *y))) + { + if(x) + { + if (y) + { + boost::swap(*x, *y); + } + else + { + y = boost::move(*x); + x = boost::none; + } + } + else + { + if (y) + { + x = boost::move(*y); + y = boost::none; + } + } + } +}; +#else template<> struct swap_selector { @@ -1268,6 +1300,7 @@ struct swap_selector } } }; +#endif // !defined BOOST_NO_CXX11_RVALUE_REFERENCES } // namespace optional_detail @@ -1275,7 +1308,7 @@ template struct optional_swap_should_use_default_constructor : has_nothrow_default_constructor {} ; template inline void swap ( optional& x, optional& y ) - BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value) + //BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && BOOST_NOEXCEPT_EXPR(boost::swap(*x, *y))) { optional_detail::swap_selector::value>::optional_swap(x, y); } diff --git a/include/boost/optional/optional_fwd.hpp b/include/boost/optional/optional_fwd.hpp index ade503d..29cee49 100644 --- a/include/boost/optional/optional_fwd.hpp +++ b/include/boost/optional/optional_fwd.hpp @@ -16,16 +16,13 @@ #ifndef BOOST_OPTIONAL_OPTIONAL_FWD_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FWD_FLC_19NOV2002_HPP #include -#include -#include namespace boost { template class optional ; -template void swap ( optional& , optional& ) - BOOST_NOEXCEPT_IF(::boost::is_nothrow_move_constructible::value && ::boost::is_nothrow_move_assignable::value); +template void swap ( optional& , optional& ); template struct optional_swap_should_use_default_constructor ; diff --git a/test/optional_test_move.cpp b/test/optional_test_move.cpp index a2d20c1..affa07f 100644 --- a/test/optional_test_move.cpp +++ b/test/optional_test_move.cpp @@ -314,6 +314,35 @@ void test_move_ctor_from_optional_U() BOOST_CHECK(b2->val == 4); } +void test_swap() +{ + optional a((MoveOnly(2))); + optional b((MoveOnly(3))); + swap(a, b); + + BOOST_CHECK(a->val == 3); + BOOST_CHECK(b->val == 2); +} + +void test_optional_ref_to_movables() +{ + MoveOnly m(3); + optional orm = m; + orm->val = 2; + BOOST_CHECK(m.val == 2); + + optional orm2 = orm; + orm2->val = 1; + BOOST_CHECK(m.val == 1); + BOOST_CHECK(orm->val == 1); + + optional orm3 = boost::move(orm); + orm3->val = 4; + BOOST_CHECK(m.val == 4); + BOOST_CHECK(orm->val == 4); + BOOST_CHECK(orm2->val == 4); +} + // these 4 classes have different noexcept signatures in move operations struct NothrowBoth { NothrowBoth(NothrowBoth&&) BOOST_NOEXCEPT_IF(true) {}; @@ -370,6 +399,8 @@ int test_main( int, char* [] ) test_move_assign_from_optional_T(); test_move_assign_from_optional_U(); test_with_move_only(); + test_optional_ref_to_movables(); + test_swap(); #endif } catch ( ... ) From c51f3e810bf8d6fcc0cba957684edcce5d40925f Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Tue, 29 Apr 2014 22:59:06 +0200 Subject: [PATCH 12/18] The (in)equality comparison with boost::none does not require that T be EqualityComparable --- .../boost_optional/detailed_semantics.html | 38 ++++++++++- doc/html/boost_optional/synopsis.html | 4 ++ .../boost_optional/type_requirements.html | 6 +- doc/html/index.html | 2 +- doc/reference.qbk | 25 ++++++- doc/special_cases.qbk | 4 +- include/boost/optional/optional.hpp | 16 ++--- test/Jamfile.v2 | 1 + test/optional_test_equals_none.cpp | 68 +++++++++++++++++++ 9 files changed, 148 insertions(+), 16 deletions(-) create mode 100644 test/optional_test_equals_none.cpp diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 77b8815..b236179 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -1497,6 +1497,10 @@ y );

    +
  • + Requires: T + shall meet requirements of EqualityComparable. +
  • Returns: If both x and y are initialized, @@ -1553,6 +1557,10 @@ y );

    +
  • + Requires: T + shall meet requirements of LessThanComparable. +
  • Returns: If y is not initialized, false. @@ -1648,7 +1656,8 @@
    • Returns: !( - y<x ); + y < + x );
    • Throws: Nothing. @@ -1673,6 +1682,33 @@ Throws: Nothing.
    +

    + bool operator + == ( optional<T> const& x, none_t + ) noexcept; +

    +
      +
    • + Returns: !x. +
    • +
    • + Notes: T + need not meet requirements of EqualityComparable. +
    • +
    +

    + space +

    +

    + bool operator + != ( optional<T> const& x, none_t + ) noexcept; +

    +
    • + Returns: !( + x == + y ); +

    space

    diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html index 8ce8e1f..95ffd46 100644 --- a/doc/html/boost_optional/synopsis.html +++ b/doc/html/boost_optional/synopsis.html @@ -122,6 +122,10 @@ template<class T> inline bool operator >= ( optional<T> const& x, optional<T> const& y ) ; R +template<class T> inline bool operator == ( optional<T> const& x, none_t ) noexcept ; R + +template<class T> inline bool operator != ( optional<T> const& x, none_t ) noexcept ; R + // [new in 1.34] template<class T> inline optional<T> make_optional ( T const& v ) ; R diff --git a/doc/html/boost_optional/type_requirements.html b/doc/html/boost_optional/type_requirements.html index 9723c4c..681d119 100644 --- a/doc/html/boost_optional/type_requirements.html +++ b/doc/html/boost_optional/type_requirements.html @@ -27,9 +27,9 @@ Type requirements

- In general, T must be Copy Constructible and - have a no-throw destructor. The copy-constructible requirement is not needed - if InPlaceFactories are used. + In general, T must be MoveConstructible and have a no-throw destructor. + The MoveConstructible requirement + is not needed if InPlaceFactories are used.

T is diff --git a/doc/html/index.html b/doc/html/index.html index ba0c93f..13a38bc 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -163,7 +163,7 @@ - +

Last revised: April 28, 2014 at 23:21:56 GMT

Last revised: April 29, 2014 at 20:56:30 GMT


diff --git a/doc/reference.qbk b/doc/reference.qbk index 04b61aa..7ea348d 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -106,6 +106,10 @@ template inline bool operator <= ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_less_or_equal_optional_optional __GO_TO__]`` template inline bool operator >= ( optional const& x, optional const& y ) ; ``[link reference_operator_compare_greater_or_equal_optional_optional __GO_TO__]`` + + template inline bool operator == ( optional const& x, none_t ) noexcept ; ``[link reference_operator_compare_equal_optional_none __GO_TO__]`` + + template inline bool operator != ( optional const& x, none_t ) noexcept ; ``[link reference_operator_compare_not_equal_optional_none __GO_TO__]`` // [new in 1.34] template inline optional make_optional ( T const& v ) ; ``[link reference_make_optional_value __GO_TO__]`` @@ -972,6 +976,7 @@ __SPACE__ [: `bool operator == ( optional const& x, optional const& y );`] +* [*Requires:] `T` shall meet requirements of `EqualityComparable`. * [*Returns:] If both `x` and `y` are initialized, `(*x == *y)`. If only `x` or `y` is initialized, `false`. If both are uninitialized, `true`. * [*Throws:] Nothing. @@ -1011,6 +1016,7 @@ __SPACE__ [: `bool operator < ( optional const& x, optional const& y );`] +* [*Requires:] `T` shall meet requirements of `LessThanComparable`. * [*Returns:] If `y` is not initialized, `false`. If `y` is initialized and `x` is not initialized, `true`. If both `x` and `y` are initialized, `(*x < *y)`. @@ -1065,7 +1071,7 @@ __SPACE__ [: `bool operator <= ( optional const& x, optional const& y );`] -* [*Returns: ] `!( y const& x, none_t ) noexcept;`] + +* [*Returns:] `!x`. +* [*Notes:] `T` need not meet requirements of `EqualityComparable`. + + +__SPACE__ + +[#reference_operator_compare_not_equal_optional_none] + +[: `bool operator != ( optional const& x, none_t ) noexcept;`] + +* [*Returns: ] `!( x == y );` + + __SPACE__ [#reference_swap_optional_optional] diff --git a/doc/special_cases.qbk b/doc/special_cases.qbk index 0f6f22b..0d7227c 100644 --- a/doc/special_cases.qbk +++ b/doc/special_cases.qbk @@ -369,8 +369,8 @@ since it is a no-op. [section Type requirements] -In general, `T` must be __COPY_CONSTRUCTIBLE__ and have a no-throw destructor. -The copy-constructible requirement is not needed if [*InPlaceFactories] are used. +In general, `T` must be `MoveConstructible` and have a no-throw destructor. +The `MoveConstructible` requirement is not needed if [*InPlaceFactories] are used. `T` [_is not] required to be __SGI_DEFAULT_CONSTRUCTIBLE__. diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index c8752af..c5e73e1 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -1143,8 +1143,8 @@ bool operator >= ( T const& x, optional const& y ) template inline -bool operator == ( optional const& x, none_t ) -{ return equal_pointees(x, optional() ); } +bool operator == ( optional const& x, none_t ) BOOST_NOEXCEPT +{ return !x; } template inline @@ -1153,8 +1153,8 @@ bool operator < ( optional const& x, none_t ) template inline -bool operator != ( optional const& x, none_t y ) -{ return !( x == y ) ; } +bool operator != ( optional const& x, none_t ) BOOST_NOEXCEPT +{ return bool(x); } template inline @@ -1177,8 +1177,8 @@ bool operator >= ( optional const& x, none_t y ) template inline -bool operator == ( none_t , optional const& y ) -{ return equal_pointees(optional() ,y); } +bool operator == ( none_t , optional const& y ) BOOST_NOEXCEPT +{ return !y; } template inline @@ -1187,8 +1187,8 @@ bool operator < ( none_t , optional const& y ) template inline -bool operator != ( none_t x, optional const& y ) -{ return !( x == y ) ; } +bool operator != ( none_t, optional const& y ) BOOST_NOEXCEPT +{ return bool(y); } template inline diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c80b783..7218ffa 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -22,6 +22,7 @@ import testing ; [ run optional_test_inplace.cpp ] [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] + [ run optional_test_equals_none.cpp ] [ compile-fail optional_test_fail1.cpp ] [ compile-fail optional_test_fail3a.cpp ] [ compile-fail optional_test_fail3b.cpp ] diff --git a/test/optional_test_equals_none.cpp b/test/optional_test_equals_none.cpp new file mode 100644 index 0000000..aed7771 --- /dev/null +++ b/test/optional_test_equals_none.cpp @@ -0,0 +1,68 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +// Revisions: +// +#include +#include +#include + +#define BOOST_ENABLE_ASSERT_HANDLER + +#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin +#include "boost/mpl/bool.hpp" +#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/none.hpp" + +#include "boost/test/minimal.hpp" + +#include "optional_test_common.cpp" + +struct SemiRegular // no operator== +{ +private: void operator==(SemiRegular const&) const {} +private: void operator!=(SemiRegular const&) const {} +}; + +void test_equal_to_none_of_noncomparable_T() +{ + optional i = SemiRegular(); + optional o; + + BOOST_CHECK(i != boost::none); + BOOST_CHECK(boost::none != i); + BOOST_CHECK(o == boost::none); + BOOST_CHECK(boost::none == o); +} + +int test_main( int, char* [] ) +{ + try + { + test_equal_to_none_of_noncomparable_T(); + + } + catch ( ... ) + { + BOOST_ERROR("Unexpected Exception caught!"); + } + + return 0; +} + + From 897fdad11b451c6079c1d347e12ebd0095046da7 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 2 May 2014 15:41:43 +0200 Subject: [PATCH 13/18] Changed incorrect types in static assertions guarding against binding temporaries to optional refs --- include/boost/optional/optional.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index c5e73e1..33f4374 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -775,7 +775,7 @@ class optional : public optional_detail::optional_base boost::is_same::type, none_t>::value >::type* = 0 ) : base(boost::forward(expr),boost::addressof(expr)) - {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref();} + {optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref();} #else template @@ -812,7 +812,7 @@ class optional : public optional_detail::optional_base >::type operator= ( Expr&& expr ) { - optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref(); + optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref(); this->assign_expr(boost::forward(expr),boost::addressof(expr)); return *this ; } From 86e759fb899eada4f2875df21c2a9743cb30a86b Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Fri, 2 May 2014 18:41:23 +0200 Subject: [PATCH 14/18] optional::rval_reference_type is now T&& (not const T&) --- include/boost/optional/optional.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 33f4374..0a01141 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -161,7 +162,7 @@ struct types_when_is_ref typedef raw_type& reference_const_type ; typedef raw_type& reference_type ; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - typedef raw_type&& rval_reference_type ; + typedef BOOST_DEDUCED_TYPENAME remove_const::type&& rval_reference_type ; static reference_type move(reference_type r) { return r; } #endif typedef raw_type* pointer_const_type ; @@ -880,6 +881,7 @@ class optional : public optional_detail::optional_base // Assigns from a T (deep-moves the rhs value) optional& operator= ( rval_reference_type val ) { + optional_detail::prevent_binding_rvalue_ref_to_optional_lvalue_ref(); this->assign( boost::move(val) ) ; return *this ; } From 6a790e0c9781db4c47d1bf8b679b7526539e8eee Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Mon, 5 May 2014 19:08:11 +0200 Subject: [PATCH 15/18] Added a test that tests the compiler if references are bound correctly. Also added the second copyright notice. --- .../a_note_about_optional_bool_.html | 2 +- doc/html/boost_optional/acknowledgments.html | 2 +- .../dependencies_and_portability.html | 2 +- .../boost_optional/detailed_semantics.html | 2 +- doc/html/boost_optional/development.html | 2 +- doc/html/boost_optional/examples.html | 2 +- .../exception_safety_guarantees.html | 2 +- .../boost_optional/implementation_notes.html | 2 +- .../boost_optional/in_place_factories.html | 2 +- .../boost_optional/optional_references.html | 2 +- ...for_assignment_of_optional_references.html | 2 +- doc/html/boost_optional/synopsis.html | 2 +- .../boost_optional/type_requirements.html | 2 +- doc/html/index.html | 3 +- doc/optional.qbk | 1 + include/boost/optional/optional.hpp | 2 + test/Jamfile.v2 | 1 + test/optional_test_the_compiler.cpp | 108 ++++++++++++++++++ 18 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 test/optional_test_the_compiler.cpp diff --git a/doc/html/boost_optional/a_note_about_optional_bool_.html b/doc/html/boost_optional/a_note_about_optional_bool_.html index c9f3a78..272a894 100644 --- a/doc/html/boost_optional/a_note_about_optional_bool_.html +++ b/doc/html/boost_optional/a_note_about_optional_bool_.html @@ -70,7 +70,7 @@ -
-
-
-
-
-
-
-
-
-
-
-
-
+

Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -163,7 +164,7 @@

- +

Last revised: April 29, 2014 at 20:56:30 GMT

Last revised: May 05, 2014 at 07:44:56 GMT


diff --git a/doc/optional.qbk b/doc/optional.qbk index fc65f14..d5608be 100644 --- a/doc/optional.qbk +++ b/doc/optional.qbk @@ -2,6 +2,7 @@ [quickbook 1.4] [authors [Cacciola Carballal, Fernando Luis]] [copyright 2003-2007 Fernando Luis Cacciola Carballal] + [copyright 2014 Andrzej Krzemieński] [category miscellaneous] [id optional] [dirname optional] diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 0a01141..0849e90 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -1,4 +1,5 @@ // Copyright (C) 2003, 2008 Fernando Luis Cacciola Carballal. +// Copyright (C) 2014 Andrzej Krzemienski. // // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -11,6 +12,7 @@ // // Revisions: // 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen +// 05 May 2014 (Added move semantics) Andrzej Krzemienski // #ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7218ffa..d9137bd 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -23,6 +23,7 @@ import testing ; [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] [ run optional_test_equals_none.cpp ] + [ run optional_test_the_compiler.cpp ] [ compile-fail optional_test_fail1.cpp ] [ compile-fail optional_test_fail3a.cpp ] [ compile-fail optional_test_fail3b.cpp ] diff --git a/test/optional_test_the_compiler.cpp b/test/optional_test_the_compiler.cpp new file mode 100644 index 0000000..dea10cb --- /dev/null +++ b/test/optional_test_the_compiler.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2014 Andrzej Krzemienski. +// +// Use, modification, and distribution is subject to 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/lib/optional for documentation. +// +// You are welcome to contact the author at: +// akrzemi1@gmail.com +// +// Revisions: +// +#include +#include +//#include + +#define BOOST_ENABLE_ASSERT_HANDLER + +//#include "boost/bind/apply.hpp" // Included just to test proper interaction with boost::apply<> as reported by Daniel Wallin +#include "boost/mpl/bool.hpp" +#include "boost/mpl/bool_fwd.hpp" // For mpl::true_ and mpl::false_ +#include "boost/static_assert.hpp" + +#include "boost/optional/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/test/minimal.hpp" +#include "optional_test_common.cpp" + + +const int global_i = 0; + +class TestingReferenceBinding +{ +public: + TestingReferenceBinding(const int& ii) + { + BOOST_CHECK(&ii == &global_i); + } + + void operator=(const int& ii) + { + BOOST_CHECK(&ii == &global_i); + } + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + void operator=(int&&) + { + BOOST_CHECK(false); + } + #endif +}; + +class TestingReferenceBinding2 // same definition as above, I need a different type +{ +public: + TestingReferenceBinding2(const int& ii) + { + BOOST_CHECK(&ii == &global_i); + } + + void operator=(const int& ii) + { + BOOST_CHECK(&ii == &global_i); + } + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + void operator=(int&&) + { + BOOST_CHECK(false); + } + #endif +}; + + +void test_broken_compiler() +{ +// we are not testing boost::optional here, but the c++ compiler +// if this test fails, optional references will obviously fail too + + const int& iref = global_i; + BOOST_CHECK(&iref == &global_i); + + TestingReferenceBinding ttt = global_i; + ttt = global_i; + + TestingReferenceBinding2 ttt2 = iref; + ttt2 = iref; +} + + +int test_main( int, char* [] ) +{ + try + { + test_broken_compiler(); + } + catch ( ... ) + { + BOOST_ERROR("Unexpected Exception caught!"); + } + + return 0; +} + + From f94846ccc5abd7395b38352218bdc3fb362f3948 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Wed, 7 May 2014 17:07:12 +0200 Subject: [PATCH 16/18] Improved documentation. Added some noexcept. --- .../dependencies_and_portability.html | 6 +- .../boost_optional/detailed_semantics.html | 18 ++- doc/html/boost_optional/development.html | 6 +- .../exception_safety_guarantees.html | 143 ++++++++++-------- .../boost_optional/implementation_notes.html | 12 +- doc/html/boost_optional/motivation.html | 128 ++++++++++++++++ .../boost_optional/optional_references.html | 17 ++- doc/html/boost_optional/synopsis.html | 4 +- .../boost_optional/type_requirements.html | 6 +- doc/html/index.html | 104 ++----------- doc/implementation_notes.qbk | 26 ---- doc/motivation.qbk | 80 ++++++++++ doc/optional.qbk | 77 ++-------- doc/reference.qbk | 15 +- doc/special_cases.qbk | 85 ++++------- include/boost/optional/optional.hpp | 6 +- test/Jamfile.v2 | 1 - 17 files changed, 405 insertions(+), 329 deletions(-) create mode 100644 doc/html/boost_optional/motivation.html delete mode 100644 doc/implementation_notes.qbk create mode 100644 doc/motivation.qbk diff --git a/doc/html/boost_optional/dependencies_and_portability.html b/doc/html/boost_optional/dependencies_and_portability.html index a4545e5..20e692b 100644 --- a/doc/html/boost_optional/dependencies_and_portability.html +++ b/doc/html/boost_optional/dependencies_and_portability.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -42,7 +42,7 @@


-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 9b01adf..8ba71b2 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -629,6 +629,22 @@ +

+ space +

+

+ optional& + optional<T>::operator= ( none_t ) noexcept; +

+
    +
  • + Effect: If *this is initialized destroys its contained + value. +
  • +
  • + Postconditions: *this is uninitialized. +
  • +

space

@@ -1122,7 +1138,7 @@ space

- void optional<T>::reset() ; + void optional<T>::reset() noexcept ;

  • Deprecated: Same as operator=( detail::none_t ); diff --git a/doc/html/boost_optional/development.html b/doc/html/boost_optional/development.html index 09a89e4..f289a04 100644 --- a/doc/html/boost_optional/development.html +++ b/doc/html/boost_optional/development.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -407,7 +407,7 @@


-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_optional/exception_safety_guarantees.html b/doc/html/boost_optional/exception_safety_guarantees.html index d95e749..eb29f92 100644 --- a/doc/html/boost_optional/exception_safety_guarantees.html +++ b/doc/html/boost_optional/exception_safety_guarantees.html @@ -28,8 +28,36 @@ Guarantees

- Because of the current implementation (see Implementation - Notes), all of the assignment methods: + This library assumes that T's + destructor does not throw exceptions. If it does, the behaviour of many operations + on optional<T> is + undefined. +

+

+ The following mutating operations never throw exceptions: +

+
    +
  • + optional<T>::operator= ( none_t ) noexcept +
  • +
  • + optional<T>::reset() noexcept +
  • +
+

+ In addition, the following constructors and the destructor never throw exceptions: +

+
    +
  • + optional<T>::optional() + noexcept +
  • +
  • + optional<T>::optional( none_t ) noexcept +
  • +
+

+ Regarding the following assignment functions:

  • @@ -52,88 +80,71 @@ )
  • - optional<T>::reset ( T const&) + optional<T>::reset( T const& )

- Can only guarantee the basic - exception safety: The lvalue optional is left uninitialized - if an exception is thrown (any previous value is first - destroyed using T::~T()) + They forward calls to the corresponding T's + constructors or assignments (depending on whether the optional object is initialized + or not); so if both T's constructor + and the assignment provide strong exception safety guarantee, optional<T>'s assignment + also provides strong exception safety guarantee; otherwise we only get the + basic guarantee. Additionally, if both involved T's + constructor and the assignment never throw, optional<T>'s + assignment also never throws.

- On the other hand, the uninitializing methods: + Unless T's constructor or assignment + throws, optional<T> does + not throw anything else on its own. A throw during assignment never changes + the initialization state of any optional object involved:

-
    -
  • - optional<T>::operator= ( detail::none_t ) -
  • -
  • - optional<T>::reset() -
  • -
-

- Provide the no-throw guarantee (assuming a no-throw T::~T()) -

-

- However, since optional<> - itself doesn't throw any exceptions, the only source for exceptions here are - T's constructor, so if you - know the exception guarantees for T::T ( - T const& ), you - know that optional's assignment - and reset has the same guarantees. -

-
//
-// Case 1: Exception thrown during assignment.
-//
-T v0(123);
-optional<T> opt0(v0);
+
optional<T> opt1(val1);
+optional<T> opt2(val2);
+assert(opt1);
+assert(opt2);
+
 try
 {
-    T v1(456);
-    optional<T> opt1(v1);
-    opt0 = opt1 ;
-
-    // If no exception was thrown, assignment succeeded.
-    assert( *opt0 == v1 ) ;
+  opt1 = opt2; // throws
 }
 catch(...)
 {
-    // If any exception was thrown, 'opt0' is reset to uninitialized.
-    assert( !opt0 ) ;
-}
-
-//
-// Case 2: Exception thrown during reset(v)
-//
-T v0(123);
-optional<T> opt(v0);
-try
-{
-    T v1(456);
-    opt.reset ( v1 ) ;
-
-    // If no exception was thrown, reset succeeded.
-    assert( *opt == v1 ) ;
-}
-catch(...)
-{
-    // If any exception was thrown, 'opt' is reset to uninitialized.
-    assert( !opt ) ;
+  assert(opt1);
+  assert(opt2);
 }
 
+

+ This also applies to move assignments/constructors. However, move operations + are made no-throw more often. +

Swap

- void swap( optional<T>&, - optional<T>& ) has the same exception guarantee as swap(T&,T&) - when both optionals are initialized. If only one of the optionals is initialized, - it gives the same basic exception guarantee as optional<T>::reset( T const& ) (since - optional<T>::reset() doesn't throw). If none of the optionals - is initialized, it has no-throw guarantee since it is a no-op. + Unless swap on optional is + customized, its primary implementation forwards calls to T's + swap or move constructor (depending + on the initialization state of the optional objects). Thus, if both T's swap + and move constructor never throw, swap + on optional<T> never + throws. similarly, if both T's + swap and move constructor offer + strong guarantee, swap on + optional<T> also + offers a strong guarantee. +

+

+ In case swap on optional is + customized, the call to T's + move constructor are replaced with the calls to T's + default constructor followed by swap. + (This is more useful on older compilers that do not support move semantics, + when one wants to acheive stronger exception safety guarantees.) In this case + the exception safety guarantees for swap + are reliant on the guarantees of T's + swap and default constructor

diff --git a/doc/html/boost_optional/implementation_notes.html b/doc/html/boost_optional/implementation_notes.html index 626e7f2..48d476c 100644 --- a/doc/html/boost_optional/implementation_notes.html +++ b/doc/html/boost_optional/implementation_notes.html @@ -31,12 +31,12 @@ currently implemented using a custom aligned storage facility built from alignment_of and type_with_alignment (both from Type Traits). It uses a separate boolean flag to indicate the initialization state. Placement new with T's - copy constructor and T's destructor - are explicitly used to initialize,copy and destroy optional values. As a result, - T's default constructor is - effectively by-passed, but the exception guarantees are basic. It is planned - to replace the current implementation with another with stronger exception - safety, such as a future boost::variant. + copy/move constructor and T's + destructor are explicitly used to initialize, copy, move and destroy optional + values. As a result, T's default + constructor is effectively by-passed, but the exception guarantees are basic. + It is planned to replace the current implementation with another with stronger + exception safety, such as a future boost::variant.

diff --git a/doc/html/boost_optional/motivation.html b/doc/html/boost_optional/motivation.html new file mode 100644 index 0000000..ee00899 --- /dev/null +++ b/doc/html/boost_optional/motivation.html @@ -0,0 +1,128 @@ + + + +Motivation + + + + + + + + +
+ + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Consider these functions which should return a value but which might not have + a value to return: +

+
    +
  • + (A) double sqrt(double n ); +
  • +
  • + (B) char get_async_input(); +
  • +
  • + (C) point polygon::get_any_point_effectively_inside(); +
  • +
+

+ There are different approaches to the issue of not having a value to return. +

+

+ A typical approach is to consider the existence of a valid return value as + a postcondition, so that if the function cannot compute the value to return, + it has either undefined behavior (and can use assert in a debug build) or uses + a runtime check and throws an exception if the postcondition is violated. This + is a reasonable choice for example, for function (A), because the lack of a + proper return value is directly related to an invalid parameter (out of domain + argument), so it is appropriate to require the callee to supply only parameters + in a valid domain for execution to continue normally. +

+

+ However, function (B), because of its asynchronous nature, does not fail just + because it can't find a value to return; so it is incorrect to consider such + a situation an error and assert or throw an exception. This function must return, + and somehow, must tell the callee that it is not returning a meaningful value. +

+

+ A similar situation occurs with function (C): it is conceptually an error to + ask a null-area polygon to return a point inside itself, + but in many applications, it is just impractical for performance reasons to + treat this as an error (because detecting that the polygon has no area might + be too expensive to be required to be tested previously), and either an arbitrary + point (typically at infinity) is returned, or some efficient way to tell the + callee that there is no such point is used. +

+

+ There are various mechanisms to let functions communicate that the returned + value is not valid. One such mechanism, which is quite common since it has + zero or negligible overhead, is to use a special value which is reserved to + communicate this. Classical examples of such special values are EOF, string::npos, points + at infinity, etc... +

+

+ When those values exist, i.e. the return type can hold all meaningful values + plus the signal value, this mechanism + is quite appropriate and well known. Unfortunately, there are cases when such + values do not exist. In these cases, the usual alternative is either to use + a wider type, such as int in place + of char; or a compound type, such + as std::pair<point,bool>. +

+

+ Returning a std::pair<T,bool>, thus attaching a boolean flag to the result + which indicates if the result is meaningful, has the advantage that can be + turned into a consistent idiom since the first element of the pair can be whatever + the function would conceptually return. For example, the last two functions + could have the following interface: +

+
std::pair<char,bool> get_async_input();
+std::pair<point,bool> polygon::get_any_point_effectively_inside();
+
+

+ These functions use a consistent interface for dealing with possibly nonexistent + results: +

+
std::pair<point,bool> p = poly.get_any_point_effectively_inside();
+if ( p.second )
+    flood_fill(p.first);
+
+

+ However, not only is this quite a burden syntactically, it is also error prone + since the user can easily use the function result (first element of the pair) + without ever checking if it has a valid value. +

+

+ Clearly, we need a better idiom. +

+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/optional_references.html b/doc/html/boost_optional/optional_references.html index fc0f684..e7e325e 100644 --- a/doc/html/boost_optional/optional_references.html +++ b/doc/html/boost_optional/optional_references.html @@ -60,7 +60,7 @@
  • Copies of optional<T&> - will copy the references but all these references will nonetheless reefer + will copy the references but all these references will nonetheless refer to the same object.
  • @@ -68,6 +68,21 @@ than the reference itself.
+
+ + + + + +
[Warning]Warning

+ On compilers that do not conform to Standard C++ rules of reference binding, + operations on optional references might give adverse results: rather than + binding a reference to a designated object they may create a temporary and + bind to it. Compilers known to have these deficiencies include GCC versions + 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. + On these compilers prefer using direct-initialization and copy assignment + of optional references to copy-initialization and assignment from T&. +

Rvalue diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html index 3963d42..075bfbf 100644 --- a/doc/html/boost_optional/synopsis.html +++ b/doc/html/boost_optional/synopsis.html @@ -60,7 +60,7 @@ template<class TypedInPlaceFactory> explicit optional ( TypedInPlaceFactory const& f ) ; R - optional& operator = ( none_t ) ; + optional& operator = ( none_t ) noexcept ; R optional& operator = ( T const& v ) ; R @@ -100,7 +100,7 @@ // deprecated methods // (deprecated) - void reset() ; R + void reset() noexcept ; R // (deprecated) void reset ( T const& ) ; R diff --git a/doc/html/boost_optional/type_requirements.html b/doc/html/boost_optional/type_requirements.html index 5080e8d..6c68e88 100644 --- a/doc/html/boost_optional/type_requirements.html +++ b/doc/html/boost_optional/type_requirements.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -47,7 +47,7 @@


-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/index.html b/doc/html/index.html index b52777d..a39d80f 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -5,7 +5,7 @@ - + @@ -17,7 +17,7 @@
More

-
Next
+
Next

@@ -37,7 +37,8 @@

- Consider these functions which should return a value but which might not have - a value to return: + This library can be used to represent 'optional' (or 'nullable') objects and + safely pass them by value:

-
    -
  • - (A) double sqrt(double n ); -
  • -
  • - (B) char get_async_input(); -
  • -
  • - (C) point polygon::get_any_point_effectively_inside(); -
  • -
-

- There are different approaches to the issue of not having a value to return. -

-

- A typical approach is to consider the existence of a valid return value as - a postcondition, so that if the function cannot compute the value to return, - it has either undefined behavior (and can use assert in a debug build) or uses - a runtime check and throws an exception if the postcondition is violated. This - is a reasonable choice for example, for function (A), because the lack of a - proper return value is directly related to an invalid parameter (out of domain - argument), so it is appropriate to require the callee to supply only parameters - in a valid domain for execution to continue normally. -

-

- However, function (B), because of its asynchronous nature, does not fail just - because it can't find a value to return; so it is incorrect to consider such - a situation an error and assert or throw an exception. This function must return, - and somehow, must tell the callee that it is not returning a meaningful value. -

-

- A similar situation occurs with function (C): it is conceptually an error to - ask a null-area polygon to return a point inside itself, - but in many applications, it is just impractical for performance reasons to - treat this as an error (because detecting that the polygon has no area might - be too expensive to be required to be tested previously), and either an arbitrary - point (typically at infinity) is returned, or some efficient way to tell the - callee that there is no such point is used. -

-

- There are various mechanisms to let functions communicate that the returned - value is not valid. One such mechanism, which is quite common since it has - zero or negligible overhead, is to use a special value which is reserved to - communicate this. Classical examples of such special values are EOF, string::npos, points - at infinity, etc... -

-

- When those values exist, i.e. the return type can hold all meaningful values - plus the signal value, this mechanism - is quite appropriate and well known. Unfortunately, there are cases when such - values do not exist. In these cases, the usual alternative is either to use - a wider type, such as int in place - of char; or a compound type, such - as std::pair<point,bool>. -

-

- Returning a std::pair<T,bool>, thus attaching a boolean flag to the result - which indicates if the result is meaningful, has the advantage that can be - turned into a consistent idiom since the first element of the pair can be whatever - the function would conceptually return. For example, the last two functions - could have the following interface: -

-
std::pair<char,bool> get_async_input();
-std::pair<point,bool> polygon::get_any_point_effectively_inside();
+
optional<int> readInt(); // this function may return either an int or a not-an-int
+
+if (optional<int> oi = readInt()) // did I get a real int
+  cout << "my int is: " << *oi;   // use my int
+else
+  cout << "I have no int";
 
-

- These functions use a consistent interface for dealing with possibly nonexistent - results: -

-
std::pair<point,bool> p = poly.get_any_point_effectively_inside();
-if ( p.second )
-    flood_fill(p.first);
-
-

- However, not only is this quite a burden syntactically, it is also error prone - since the user can easily use the function result (first element of the pair) - without ever checking if it has a valid value. -

-

- Clearly, we need a better idiom. -

- +

Last revised: May 05, 2014 at 07:44:56 GMT

Last revised: May 07, 2014 at 15:05:52 GMT


-
Next
+
Next
diff --git a/doc/implementation_notes.qbk b/doc/implementation_notes.qbk deleted file mode 100644 index 53e6138..0000000 --- a/doc/implementation_notes.qbk +++ /dev/null @@ -1,26 +0,0 @@ -[/ - Boost.Optional - - Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal - - 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) -] - - - -[section Implementation Notes] - -`optional` is currently implemented using a custom aligned storage facility -built from `alignment_of` and `type_with_alignment` (both from Type Traits). It -uses a separate boolean flag to indicate the initialization state. -Placement new with `T`'s copy constructor and `T`'s destructor are explicitly used -to initialize,copy and destroy optional values. -As a result, `T`'s default constructor is effectively by-passed, but the exception -guarantees are basic. -It is planned to replace the current implementation with another with stronger -exception safety, such as a future `boost::variant`. - -[endsect] - diff --git a/doc/motivation.qbk b/doc/motivation.qbk new file mode 100644 index 0000000..fc014c3 --- /dev/null +++ b/doc/motivation.qbk @@ -0,0 +1,80 @@ +[/ + Boost.Optional + + Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal + Copyright (c) 2014 Andrzej Krzemienski + + 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) +] + +[section Motivation] + +Consider these functions which should return a value but which might not have +a value to return: + +* (A) `double sqrt(double n );` +* (B) `char get_async_input();` +* (C) `point polygon::get_any_point_effectively_inside();` + +There are different approaches to the issue of not having a value to return. + +A typical approach is to consider the existence of a valid return value as a +postcondition, so that if the function cannot compute the value to return, it +has either undefined behavior (and can use assert in a debug build) or uses a +runtime check and throws an exception if the postcondition is violated. This +is a reasonable choice for example, for function (A), because the lack of a +proper return value is directly related to an invalid parameter (out of domain +argument), so it is appropriate to require the callee to supply only parameters +in a valid domain for execution to continue normally. + +However, function (B), because of its asynchronous nature, does not fail just +because it can't find a value to return; so it is incorrect to consider such +a situation an error and assert or throw an exception. This function must +return, and somehow, must tell the callee that it is not returning a meaningful +value. + +A similar situation occurs with function (C): it is conceptually an error to +ask a ['null-area] polygon to return a point inside itself, but in many +applications, it is just impractical for performance reasons to treat this as +an error (because detecting that the polygon has no area might be too expensive +to be required to be tested previously), and either an arbitrary point +(typically at infinity) is returned, or some efficient way to tell the callee +that there is no such point is used. + +There are various mechanisms to let functions communicate that the returned +value is not valid. One such mechanism, which is quite common since it has +zero or negligible overhead, is to use a special value which is reserved to +communicate this. Classical examples of such special values are `EOF`, +`string::npos`, points at infinity, etc... + +When those values exist, i.e. the return type can hold all meaningful values +['plus] the ['signal] value, this mechanism is quite appropriate and well known. +Unfortunately, there are cases when such values do not exist. In these cases, +the usual alternative is either to use a wider type, such as `int` in place of +`char`; or a compound type, such as `std::pair`. + +Returning a `std::pair`, thus attaching a boolean flag to the result +which indicates if the result is meaningful, has the advantage that can be +turned into a consistent idiom since the first element of the pair can be +whatever the function would conceptually return. For example, the last two +functions could have the following interface: + + std::pair get_async_input(); + std::pair polygon::get_any_point_effectively_inside(); + +These functions use a consistent interface for dealing with possibly nonexistent +results: + + std::pair p = poly.get_any_point_effectively_inside(); + if ( p.second ) + flood_fill(p.first); + +However, not only is this quite a burden syntactically, it is also error prone +since the user can easily use the function result (first element of the pair) +without ever checking if it has a valid value. + +Clearly, we need a better idiom. + +[endsect] \ No newline at end of file diff --git a/doc/optional.qbk b/doc/optional.qbk index d5608be..b81f958 100644 --- a/doc/optional.qbk +++ b/doc/optional.qbk @@ -45,82 +45,23 @@ Distributed under the Boost Software License, Version 1.0. [def __GO_TO__ [$images/callouts/R.png]] -[section Motivation] +[section Introduction] +This library can be used to represent 'optional' (or 'nullable') objects and safely pass them by value: -Consider these functions which should return a value but which might not have -a value to return: - -* (A) `double sqrt(double n );` -* (B) `char get_async_input();` -* (C) `point polygon::get_any_point_effectively_inside();` - -There are different approaches to the issue of not having a value to return. - -A typical approach is to consider the existence of a valid return value as a -postcondition, so that if the function cannot compute the value to return, it -has either undefined behavior (and can use assert in a debug build) or uses a -runtime check and throws an exception if the postcondition is violated. This -is a reasonable choice for example, for function (A), because the lack of a -proper return value is directly related to an invalid parameter (out of domain -argument), so it is appropriate to require the callee to supply only parameters -in a valid domain for execution to continue normally. - -However, function (B), because of its asynchronous nature, does not fail just -because it can't find a value to return; so it is incorrect to consider such -a situation an error and assert or throw an exception. This function must -return, and somehow, must tell the callee that it is not returning a meaningful -value. - -A similar situation occurs with function (C): it is conceptually an error to -ask a ['null-area] polygon to return a point inside itself, but in many -applications, it is just impractical for performance reasons to treat this as -an error (because detecting that the polygon has no area might be too expensive -to be required to be tested previously), and either an arbitrary point -(typically at infinity) is returned, or some efficient way to tell the callee -that there is no such point is used. - -There are various mechanisms to let functions communicate that the returned -value is not valid. One such mechanism, which is quite common since it has -zero or negligible overhead, is to use a special value which is reserved to -communicate this. Classical examples of such special values are `EOF`, -`string::npos`, points at infinity, etc... - -When those values exist, i.e. the return type can hold all meaningful values -['plus] the ['signal] value, this mechanism is quite appropriate and well known. -Unfortunately, there are cases when such values do not exist. In these cases, -the usual alternative is either to use a wider type, such as `int` in place of -`char`; or a compound type, such as `std::pair`. - -Returning a `std::pair`, thus attaching a boolean flag to the result -which indicates if the result is meaningful, has the advantage that can be -turned into a consistent idiom since the first element of the pair can be -whatever the function would conceptually return. For example, the last two -functions could have the following interface: - - std::pair get_async_input(); - std::pair polygon::get_any_point_effectively_inside(); - -These functions use a consistent interface for dealing with possibly nonexistent -results: - - std::pair p = poly.get_any_point_effectively_inside(); - if ( p.second ) - flood_fill(p.first); - -However, not only is this quite a burden syntactically, it is also error prone -since the user can easily use the function result (first element of the pair) -without ever checking if it has a valid value. - -Clearly, we need a better idiom. + optional readInt(); // this function may return either an int or a not-an-int + if (optional oi = readInt()) // did I get a real int + cout << "my int is: " << *oi; // use my int + else + cout << "I have no int"; + [endsect] - +[include motivation.qbk] [include development.qbk] [include reference.qbk] [include examples.qbk] [include special_cases.qbk] -[include implementation_notes.qbk] [include dependencies.qbk] [include acknowledgments.qbk] diff --git a/doc/reference.qbk b/doc/reference.qbk index 7ea348d..1c9a6bb 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -45,7 +45,7 @@ template explicit optional ( TypedInPlaceFactory const& f ) ; ``[link reference_optional_constructor_factory __GO_TO__]`` - optional& operator = ( none_t ) ; ``[/[link reference_optional_operator_equal_none_t __GO_TO__]]`` + optional& operator = ( none_t ) noexcept ; ``[link reference_optional_operator_equal_none_t __GO_TO__]`` optional& operator = ( T const& v ) ; ``[link reference_optional_operator_equal_value __GO_TO__]`` @@ -85,7 +85,7 @@ // deprecated methods // (deprecated) - void reset() ; ``[link reference_optional_reset __GO_TO__]`` + void reset() noexcept ; ``[link reference_optional_reset __GO_TO__]`` // (deprecated) void reset ( T const& ) ; ``[link reference_optional_reset_value __GO_TO__]`` @@ -483,6 +483,15 @@ assert ( *y == v ) ; __SPACE__ +[#reference_optional_operator_equal_none_t] + +[: `optional& optional::operator= ( none_t ) noexcept;`] + +* [*Effect:] If `*this` is initialized destroys its contained value. +* [*Postconditions: ] `*this` is uninitialized. + +__SPACE__ + [#reference_optional_operator_equal_value] [: `optional& optional::operator= ( T const& rhs ) ;`] @@ -762,7 +771,7 @@ __SPACE__ [#reference_optional_reset] -[: `void optional::reset() ;`] +[: `void optional::reset() noexcept ;`] * [*Deprecated:] Same as `operator=( detail::none_t );` __SPACE__ diff --git a/doc/special_cases.qbk b/doc/special_cases.qbk index 0d7227c..145209d 100644 --- a/doc/special_cases.qbk +++ b/doc/special_cases.qbk @@ -17,10 +17,12 @@ Also, even though `optional` treats it wrapped pseudo-object much as a real value, a true real reference is stored so aliasing will ocurr: * Copies of `optional` will copy the references but all these references -will nonetheless reefer to the same object. +will nonetheless refer to the same object. * Value-access will actually provide access to the referenced object rather than the reference itself. +[warning On compilers that do not conform to Standard C++ rules of reference binding, operations on optional references might give adverse results: rather than binding a reference to a designated object they may create a temporary and bind to it. Compilers known to have these deficiencies include GCC versions 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. On these compilers prefer using direct-initialization and copy assignment of optional references to copy-initialization and assignment from `T&`.] + [heading Rvalue references] Rvalue references and lvalue references to const have the ability in C++ to extend the life time of a temporary they bind to. Optional references do not have this capability, therefore to avoid surprising effects it is not possible to initialize an optional references from a temporary. Optional rvalue references are disabled altogether. Also, the initialization and assignment of an optional reference to const from rvalue reference is disabled. @@ -291,80 +293,55 @@ instead, it won't compile). [section Exception Safety Guarantees] -Because of the current implementation (see [link boost_optional.implementation_notes Implementation Notes]), all of the assignment methods: +This library assumes that `T`'s destructor does not throw exceptions. If it does, the behaviour of many operations on `optional` is undefined. + +The following mutating operations never throw exceptions: + +* `optional::operator= ( none_t ) noexcept` +* `optional::reset() noexcept` + +In addition, the following constructors and the destructor never throw exceptions: + +* `optional::optional() noexcept` +* `optional::optional( none_t ) noexcept` + + +Regarding the following assignment functions: * `optional::operator= ( optional const& )` * `optional::operator= ( T const& )` * `template optional::operator= ( optional const& )` * `template optional::operator= ( InPlaceFactory const& )` * `template optional::operator= ( TypedInPlaceFactory const& ) ` -* `optional::reset ( T const&)` +* `optional::reset( T const& )` -Can only ['guarantee] the [_basic exception safety]: The lvalue optional is -left [_uninitialized] if an exception is thrown (any previous value is ['first] -destroyed using `T::~T()`) +They forward calls to the corresponding `T`'s constructors or assignments (depending on whether the optional object is initialized or not); so if both `T`'s constructor and the assignment provide strong exception safety guarantee, `optional`'s assignment also provides strong exception safety guarantee; otherwise we only get the basic guarantee. Additionally, if both involved `T`'s constructor and the assignment never throw, `optional`'s assignment also never throws. -On the other hand, the ['uninitializing] methods: +Unless `T`'s constructor or assignment throws, `optional` does not throw anything else on its own. A throw during assignment never changes the initialization state of any optional object involved: -* `optional::operator= ( detail::none_t )` -* `optional::reset()` -Provide the no-throw guarantee (assuming a no-throw `T::~T()`) - -However, since `optional<>` itself doesn't throw any exceptions, the only -source for exceptions here are `T`'s constructor, so if you know the exception -guarantees for `T::T ( T const& )`, you know that `optional`'s assignment and -reset has the same guarantees. - - // - // Case 1: Exception thrown during assignment. - // - T v0(123); - optional opt0(v0); + optional opt1(val1); + optional opt2(val2); + assert(opt1); + assert(opt2); + try { - T v1(456); - optional opt1(v1); - opt0 = opt1 ; - - // If no exception was thrown, assignment succeeded. - assert( *opt0 == v1 ) ; + opt1 = opt2; // throws } catch(...) { - // If any exception was thrown, 'opt0' is reset to uninitialized. - assert( !opt0 ) ; + assert(opt1); + assert(opt2); } - // - // Case 2: Exception thrown during reset(v) - // - T v0(123); - optional opt(v0); - try - { - T v1(456); - opt.reset ( v1 ) ; - - // If no exception was thrown, reset succeeded. - assert( *opt == v1 ) ; - } - catch(...) - { - // If any exception was thrown, 'opt' is reset to uninitialized. - assert( !opt ) ; - } +This also applies to move assignments/constructors. However, move operations are made no-throw more often. [heading Swap] -`void swap( optional&, optional& )` has the same exception guarantee -as `swap(T&,T&)` when both optionals are initialized. -If only one of the optionals is initialized, it gives the same ['basic] -exception guarantee as `optional::reset( T const& )` (since -`optional::reset()` doesn't throw). -If none of the optionals is initialized, it has no-throw guarantee -since it is a no-op. +Unless `swap` on optional is customized, its primary implementation forwards calls to `T`'s `swap` or move constructor (depending on the initialization state of the optional objects). Thus, if both `T`'s `swap` and move constructor never throw, `swap` on `optional` never throws. similarly, if both `T`'s `swap` and move constructor offer strong guarantee, `swap` on `optional` also offers a strong guarantee. +In case `swap` on optional is customized, the call to `T`'s move constructor are replaced with the calls to `T`'s default constructor followed by `swap`. (This is more useful on older compilers that do not support move semantics, when one wants to acheive stronger exception safety guarantees.) In this case the exception safety guarantees for `swap` are reliant on the guarantees of `T`'s `swap` and default constructor [endsect] [section Type requirements] diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 0849e90..72f5ab9 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -405,7 +405,7 @@ class optional_base : public optional_tag // Assigns from "none", destroying the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) - void assign ( none_t ) { destroy(); } + void assign ( none_t ) BOOST_NOEXCEPT { destroy(); } #ifndef BOOST_OPTIONAL_NO_INPLACE_FACTORY_SUPPORT @@ -433,7 +433,7 @@ class optional_base : public optional_tag // Destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) - void reset() { destroy(); } + void reset() BOOST_NOEXCEPT { destroy(); } // Replaces the current value -if any- with 'val' void reset ( argument_type val ) { assign(val); } @@ -892,7 +892,7 @@ class optional : public optional_detail::optional_base // Assigns from a "none" // Which destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) - optional& operator= ( none_t none_ ) + optional& operator= ( none_t none_ ) BOOST_NOEXCEPT { this->assign( none_ ) ; return *this ; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d9137bd..7218ffa 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -23,7 +23,6 @@ import testing ; [ run optional_test_io.cpp ] [ run optional_test_move.cpp ] [ run optional_test_equals_none.cpp ] - [ run optional_test_the_compiler.cpp ] [ compile-fail optional_test_fail1.cpp ] [ compile-fail optional_test_fail3a.cpp ] [ compile-fail optional_test_fail3b.cpp ] From 1c9775a9d9dcb3597d3c7e6a2feb00e73ccfa0cc Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Thu, 8 May 2014 21:50:41 +0200 Subject: [PATCH 17/18] docs: described optional reference binding issues --- doc/dependencies.qbk | 50 +++++++++++++++ .../a_note_about_optional_bool_.html | 34 ++++++++-- .../dependencies_and_portability.html | 64 +++++++++++++++++++ .../boost_optional/detailed_semantics.html | 6 +- .../boost_optional/optional_references.html | 8 +-- doc/html/index.html | 8 ++- doc/optional.qbk | 2 +- doc/reference.qbk | 2 +- doc/special_cases.qbk | 31 +++++++-- 9 files changed, 181 insertions(+), 24 deletions(-) diff --git a/doc/dependencies.qbk b/doc/dependencies.qbk index 6aa0eb5..fce4ca8 100644 --- a/doc/dependencies.qbk +++ b/doc/dependencies.qbk @@ -14,4 +14,54 @@ The implementation uses `type_traits/alignment_of.hpp` and `type_traits/type_with_alignment.hpp` +[section Optional Reference Binding] + +On compilers that do not conform to Standard C++ rules of reference binding, operations on optional references might give adverse results: rather than binding a reference to a designated object they may create an unexpected temporary and bind to it. Compilers known to have these deficiencies include GCC versions 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. On these compilers prefer using direct-initialization and copy assignment of optional references to copy-initialization and assignment from `T&`: + + const int i = 0; + optional or1; + optional or2 = i; // not portable + or1 = i; // not portable + + optional or3(i); // portable + or1 = optional(i); // portable + +In order to check if your compiler correctly implements reference binding use this test program. + + #include + + const int global_i = 0; + + struct TestingReferenceBinding + { + TestingReferenceBinding(const int& ii) + { + assert(&ii == &global_i); + } + + void operator=(const int& ii) + { + assert(&ii == &global_i); + } + + void operator=(int&&) // remove this if your compiler doesn't have rvalue refs + { + assert(false); + } + }; + + int main() + { + const int& iref = global_i; + assert(&iref == &global_i); + + TestingReferenceBinding ttt = global_i; + ttt = global_i; + + TestingReferenceBinding ttt2 = iref; + ttt2 = iref; + } + +[endsect] + [endsect] \ No newline at end of file diff --git a/doc/html/boost_optional/a_note_about_optional_bool_.html b/doc/html/boost_optional/a_note_about_optional_bool_.html index 272a894..169813c 100644 --- a/doc/html/boost_optional/a_note_about_optional_bool_.html +++ b/doc/html/boost_optional/a_note_about_optional_bool_.html @@ -32,7 +32,7 @@ be used with special caution and consideration.

- First, it is functionally similar to a tristate boolean (false,maybe,true) + First, it is functionally similar to a tristate boolean (false, maybe, true) —such as boost::tribool— except that in a tristate boolean, the maybe state represents a valid value, unlike the corresponding state of an uninitialized @@ -42,10 +42,11 @@ needed.

- Second, optional<> - provides an implicit conversion to bool. - This conversion refers to the initialization state and not to the contained - value. Using optional<bool> can + Second, although optional<> + provides a contextual conversion to bool + in C++11, this falls back to an implicit conversion on older compilers. This + conversion refers to the initialization state and not to the contained value. + Using optional<bool> can lead to subtle errors due to the implicit bool conversion:

@@ -67,6 +68,29 @@ takes an int instead, it won't compile).

+

+ Third, mixed comparisons with bool + work differently than similar mixed comparisons between pointers and bool, so the results might surprise you: +

+
optional<bool> oEmpty(none), oTrue(true), oFalse(false);
+
+if (oEmpty == none);  // renders true
+if (oEmpty == false); // renders false!
+if (oEmpty == true);  // renders false!
+
+if (oFalse == none);  // renders false
+if (oFalse == false); // renders true!
+if (oFalse == true);  // renders false
+
+if (oTrue == none);   // renders false
+if (oTrue == false);  // renders false
+if (oTrue == true);   // renders true
+
+

+ In other words, for optional<>, the following assertion does not hold: +

+
assert((opt == false) == (!opt));
+
diff --git a/doc/html/boost_optional/dependencies_and_portability.html b/doc/html/boost_optional/dependencies_and_portability.html index 20e692b..5049104 100644 --- a/doc/html/boost_optional/dependencies_and_portability.html +++ b/doc/html/boost_optional/dependencies_and_portability.html @@ -27,10 +27,74 @@ Dependencies and Portability +

The implementation uses type_traits/alignment_of.hpp and type_traits/type_with_alignment.hpp

+
+ +

+ On compilers that do not conform to Standard C++ rules of reference binding, + operations on optional references might give adverse results: rather than + binding a reference to a designated object they may create an unexpected + temporary and bind to it. Compilers known to have these deficiencies include + GCC versions 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, + 11.0, 12.0. On these compilers prefer using direct-initialization and copy + assignment of optional references to copy-initialization and assignment from + T&: +

+
const int i = 0;
+optional<const int&> or1;
+optional<const int&> or2 = i;  // not portable
+or1 = i;                       // not portable
+
+optional<const int&> or3(i);   // portable
+or1 = optional<const int&>(i); // portable
+
+

+ In order to check if your compiler correctly implements reference binding + use this test program. +

+
#include <cassert>
+
+const int global_i = 0;
+
+struct TestingReferenceBinding
+{
+  TestingReferenceBinding(const int& ii)
+  {
+    assert(&ii == &global_i);
+  }
+
+  void operator=(const int& ii)
+  {
+    assert(&ii == &global_i);
+  }
+
+  void operator=(int&&) // remove this if your compiler doesn't have rvalue refs
+  {
+    assert(false);
+  }
+};
+
+int main()
+{
+  const int& iref = global_i;
+  assert(&iref == &global_i);
+
+  TestingReferenceBinding ttt = global_i;
+  ttt = global_i;
+
+  TestingReferenceBinding ttt2 = iref;
+  ttt2 = iref;
+}
+
+
diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 8ba71b2..4a5394e 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -1446,9 +1446,9 @@ const;

  • - Deprecated: Same as operator - unspecified-bool-type() - ; + Deprecated: Same as explicit + operator bool + () ;

space diff --git a/doc/html/boost_optional/optional_references.html b/doc/html/boost_optional/optional_references.html index e7e325e..2b36c3e 100644 --- a/doc/html/boost_optional/optional_references.html +++ b/doc/html/boost_optional/optional_references.html @@ -76,11 +76,9 @@

On compilers that do not conform to Standard C++ rules of reference binding, operations on optional references might give adverse results: rather than - binding a reference to a designated object they may create a temporary and - bind to it. Compilers known to have these deficiencies include GCC versions - 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. - On these compilers prefer using direct-initialization and copy assignment - of optional references to copy-initialization and assignment from T&. + binding a reference to a designated object they may create an unexpected + temporary and bind to it. For more details see Dependencies + and Portability section.

diff --git a/doc/html/index.html b/doc/html/index.html index a39d80f..1bb9006 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -69,6 +69,8 @@
Type requirements
Dependencies and Portability
+
Optional + Reference Binding
Acknowledgments

@@ -77,8 +79,8 @@ Introduction

- This library can be used to represent 'optional' (or 'nullable') objects and - safely pass them by value: + This library can be used to represent 'optional' (or 'nullable') objects that + can be safely passed by value:

optional<int> readInt(); // this function may return either an int or a not-an-int
 
@@ -90,7 +92,7 @@
 
 
 
-
+

Last revised: May 07, 2014 at 15:05:52 GMT

Last revised: May 08, 2014 at 12:05:10 GMT


diff --git a/doc/optional.qbk b/doc/optional.qbk index b81f958..3a74566 100644 --- a/doc/optional.qbk +++ b/doc/optional.qbk @@ -46,7 +46,7 @@ Distributed under the Boost Software License, Version 1.0. [section Introduction] -This library can be used to represent 'optional' (or 'nullable') objects and safely pass them by value: +This library can be used to represent 'optional' (or 'nullable') objects that can be safely passed by value: optional readInt(); // this function may return either an int or a not-an-int diff --git a/doc/reference.qbk b/doc/reference.qbk index 1c9a6bb..5cbaf6b 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -939,7 +939,7 @@ __SPACE__ [: `bool optional::is_initialized() const ;`] -* [*Deprecated:] Same as `operator `['unspecified-bool-type]`() ;` +* [*Deprecated:] Same as `explicit operator bool () ;` __SPACE__ diff --git a/doc/special_cases.qbk b/doc/special_cases.qbk index 145209d..adc191e 100644 --- a/doc/special_cases.qbk +++ b/doc/special_cases.qbk @@ -21,7 +21,7 @@ will nonetheless refer to the same object. * Value-access will actually provide access to the referenced object rather than the reference itself. -[warning On compilers that do not conform to Standard C++ rules of reference binding, operations on optional references might give adverse results: rather than binding a reference to a designated object they may create a temporary and bind to it. Compilers known to have these deficiencies include GCC versions 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. On these compilers prefer using direct-initialization and copy assignment of optional references to copy-initialization and assignment from `T&`.] +[warning On compilers that do not conform to Standard C++ rules of reference binding, operations on optional references might give adverse results: rather than binding a reference to a designated object they may create an unexpected temporary and bind to it. For more details see [link boost_optional.dependencies_and_portability.optional_reference_binding Dependencies and Portability section].] [heading Rvalue references] @@ -262,17 +262,17 @@ The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYP `optional` should be used with special caution and consideration. -First, it is functionally similar to a tristate boolean (false,maybe,true) +First, it is functionally similar to a tristate boolean (false, maybe, true) —such as __BOOST_TRIBOOL__— except that in a tristate boolean, the maybe state [_represents a valid value], unlike the corresponding state of an uninitialized `optional`. It should be carefully considered if an `optional` instead of a `tribool` is really needed. -Second, `optional<>` provides an implicit conversion to `bool`. This -conversion refers to the initialization state and not to the contained value. -Using `optional` can lead to subtle errors due to the implicit `bool` -conversion: +Second, although `optional<>` provides a contextual conversion to `bool` in C++11, + this falls back to an implicit conversion on older compilers. This conversion refers + to the initialization state and not to the contained value. Using `optional` + can lead to subtle errors due to the implicit `bool` conversion: void foo ( bool v ) ; void bar() @@ -289,6 +289,25 @@ The only implicit conversion is to `bool`, and it is safe in the sense that typical integral promotions don't apply (i.e. if `foo()` takes an `int` instead, it won't compile). +Third, mixed comparisons with `bool` work differently than similar mixed comparisons between pointers and `bool`, so the results might surprise you: + + optional oEmpty(none), oTrue(true), oFalse(false); + + if (oEmpty == none); // renders true + if (oEmpty == false); // renders false! + if (oEmpty == true); // renders false! + + if (oFalse == none); // renders false + if (oFalse == false); // renders true! + if (oFalse == true); // renders false + + if (oTrue == none); // renders false + if (oTrue == false); // renders false + if (oTrue == true); // renders true + +In other words, for `optional<>`, the following assertion does not hold: + + assert((opt == false) == (!opt)); [endsect] [section Exception Safety Guarantees] From e9f5ed41be7139fdaf62e928e75156cdc1cf09d9 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Tue, 13 May 2014 14:11:17 +0200 Subject: [PATCH 18/18] binding to rvalues can be reenabled with a macro --- include/boost/optional/optional.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 72f5ab9..57fa522 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -175,9 +175,11 @@ struct types_when_is_ref template void prevent_binding_rvalue_ref_to_optional_lvalue_ref() { +#ifndef BOOST_OPTIONAL_ALLOW_BINDING_TO_RVALUES BOOST_STATIC_ASSERT_MSG( !boost::is_lvalue_reference::value || !boost::is_rvalue_reference::value, - "binding rvalue references to optional lvalue references is disallowed"); + "binding rvalue references to optional lvalue references is disallowed"); +#endif } struct optional_tag {} ;