From 7ea2ca6c405ae7c49837b54438757f9e745d563b Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 19 Nov 2016 14:57:40 +0100 Subject: [PATCH 1/6] Fix #12563 --- include/boost/optional/optional.hpp | 14 ++++++++-- test/optional_test_convert_from_T.cpp | 26 ++++++++++++++++++- ...tional_test_sfinae_friendly_value_ctor.cpp | 17 +++++++++--- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 021588f..ef62aa7 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -745,6 +745,10 @@ struct is_convertible_to_T_or_factory , boost::true_type, boost::false_type>::type {}; +template +struct is_optional_constructible : boost::is_constructible +{}; + #else #define BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT @@ -753,6 +757,10 @@ template struct is_convertible_to_T_or_factory : boost::true_type {}; +template +struct is_optional_constructible : boost::true_type +{}; + #endif // is_convertible condition template @@ -812,7 +820,8 @@ class optional : public optional_detail::optional_base // Requires a valid conversion from U to T. // Can throw if T::T(U const&) does template - explicit optional ( optional const& rhs ) + explicit optional ( optional const& rhs, + typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0) : base() { @@ -825,7 +834,8 @@ class optional : public optional_detail::optional_base // Requires a valid conversion from U to T. // Can throw if T::T(U&&) does template - explicit optional ( optional && rhs ) + explicit optional ( optional && rhs, + typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0 ) : base() { diff --git a/test/optional_test_convert_from_T.cpp b/test/optional_test_convert_from_T.cpp index d4ce4bb..2abe7e5 100644 --- a/test/optional_test_convert_from_T.cpp +++ b/test/optional_test_convert_from_T.cpp @@ -23,6 +23,29 @@ using boost::optional; using boost::none; +template +struct superconv +{ + #ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + template + superconv(T&&) { BOOST_STATIC_ASSERT(sizeof(T) == 0); } + #else + template + superconv(const T&) { BOOST_STATIC_ASSERT(sizeof(T) == 0); } + template + superconv( T&) { BOOST_STATIC_ASSERT(sizeof(T) == 0); } + #endif + + superconv() {} +}; + +void test_optional_of_superconverting_T() // compile-time test +{ + superconv > s; + superconv > & rs = s; + optional > > os = rs; +} + void test_optional_optional_T() { optional oi1 (1), oiN; @@ -39,6 +62,7 @@ void test_optional_optional_T() int main() { test_optional_optional_T(); - + test_optional_of_superconverting_T(); + return boost::report_errors(); } diff --git a/test/optional_test_sfinae_friendly_value_ctor.cpp b/test/optional_test_sfinae_friendly_value_ctor.cpp index d7af15d..6c2abda 100644 --- a/test/optional_test_sfinae_friendly_value_ctor.cpp +++ b/test/optional_test_sfinae_friendly_value_ctor.cpp @@ -27,11 +27,20 @@ struct Resource explicit Resource(const X&) {} }; -BOOST_STATIC_ASSERT(( boost::is_constructible::value)); -BOOST_STATIC_ASSERT((!boost::is_constructible::value)); +BOOST_STATIC_ASSERT(( boost::is_constructible::value )); +BOOST_STATIC_ASSERT(( !boost::is_constructible::value )); -BOOST_STATIC_ASSERT(( boost::is_constructible, const X&>::value)); -BOOST_STATIC_ASSERT((!boost::is_constructible, const Y&>::value)); +BOOST_STATIC_ASSERT(( boost::is_constructible, const X&>::value )); +BOOST_STATIC_ASSERT(( !boost::is_constructible, const Y&>::value )); + +BOOST_STATIC_ASSERT(( boost::is_constructible< optional< optional >, optional >::value )); +BOOST_STATIC_ASSERT(( !boost::is_constructible< optional, optional< optional > >::value )); + +BOOST_STATIC_ASSERT(( boost::is_constructible< optional< optional >, const optional& >::value )); +BOOST_STATIC_ASSERT(( !boost::is_constructible< optional, const optional< optional >& >::value )); + +BOOST_STATIC_ASSERT(( boost::is_constructible, const optional&>::value )); +BOOST_STATIC_ASSERT(( !boost::is_constructible, const optional&>::value )); #endif From fafb3abb64987bd9a6d2bdcb1ec012b40a38cf6f Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 19 Nov 2016 21:14:28 +0100 Subject: [PATCH 2/6] Implemented reset syntax: o = {} --- include/boost/optional/optional.hpp | 26 ++++++++----- test/Jamfile.v2 | 1 + test/optional_test_empty_braces.cpp | 57 +++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 test/optional_test_empty_braces.cpp diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index ef62aa7..22c53a2 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -741,7 +741,7 @@ template struct is_convertible_to_T_or_factory : boost::conditional< boost::is_base_of::type>::value || boost::is_base_of::type>::value - || boost::is_constructible::value + || (boost::is_constructible::value && !boost::is_same::type>::value) , boost::true_type, boost::false_type>::type {}; @@ -954,6 +954,19 @@ class optional : public optional_detail::optional_base } #endif + +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + + // Assigns from a T (deep-moves/copies the rhs value) + template + BOOST_DEDUCED_TYPENAME boost::enable_if::type>, optional&>::type + operator= ( T_&& val ) + { + this->assign( boost::forward(val) ) ; + return *this ; + } +#else + // 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 ) @@ -961,16 +974,9 @@ class optional : public optional_detail::optional_base this->assign( val ) ; return *this ; } - -#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES - // Assigns from a T (deep-moves the rhs value) - optional& operator= ( rval_reference_type val ) - { - this->assign( boost::move(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) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ec93e18..919ba67 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -21,6 +21,7 @@ import testing ; [ run optional_test_swap.cpp ] [ run optional_test_conversions_from_U.cpp ] [ run optional_test_convert_from_T.cpp ] + [ run optional_test_empty_braces.cpp ] [ run optional_test_tie.cpp ] [ run optional_test_ref_assign_portable_minimum.cpp ] [ run optional_test_ref_assign_mutable_int.cpp ] diff --git a/test/optional_test_empty_braces.cpp b/test/optional_test_empty_braces.cpp new file mode 100644 index 0000000..593a68f --- /dev/null +++ b/test/optional_test_empty_braces.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2016 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/optional.hpp" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#include "boost/core/lightweight_test.hpp" + +//#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT +//#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR + +using boost::optional; + +struct Value +{ + explicit Value(int) {} +}; + +#ifndef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +template +void test_brace_init() +{ + optional o = {}; + BOOST_TEST(!o); +} + +template +void test_brace_assign() +{ + optional o; + o = {}; + BOOST_TEST(!o); +} +#endif + +int main() +{ +#ifndef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX + test_brace_init(); + test_brace_init(); + test_brace_assign(); + test_brace_assign(); +#endif + + return boost::report_errors(); +} From b4907c2a510f64af0ee87c490a706f86091d9844 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sun, 20 Nov 2016 23:42:41 +0100 Subject: [PATCH 3/6] old compiler workarounds for the previous two fixes --- .../boost/optional/detail/optional_config.hpp | 13 ++++++++ include/boost/optional/optional.hpp | 33 ++++++++++++------- test/Jamfile.v2 | 2 +- ...=> optional_test_sfinae_friendly_ctor.cpp} | 2 ++ 4 files changed, 38 insertions(+), 12 deletions(-) rename test/{optional_test_sfinae_friendly_value_ctor.cpp => optional_test_sfinae_friendly_ctor.cpp} (95%) diff --git a/include/boost/optional/detail/optional_config.hpp b/include/boost/optional/detail/optional_config.hpp index 648744e..5c388fb 100644 --- a/include/boost/optional/detail/optional_config.hpp +++ b/include/boost/optional/detail/optional_config.hpp @@ -96,4 +96,17 @@ #endif // defined(__GNUC__) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_DECLTYPE) && !BOOST_WORKAROUND(BOOST_MSVC, < 1800) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40500) && !defined(__SUNPRO_CC) + // this condition is a copy paste from is_constructible.hpp + // I also disable SUNPRO, as it seems not to support type_traits correctly +#else +# define BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT +#endif + +#if defined __SUNPRO_CC +# define BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS +#elif (defined _MSC_FULL_VER) && (_MSC_FULL_VER < 190023026) +# define BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS +#endif + #endif // header guard diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 22c53a2..e450898 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -733,9 +733,7 @@ struct is_optional_related boost::true_type, boost::false_type>::type {}; -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_DECLTYPE) && !BOOST_WORKAROUND(BOOST_MSVC, < 1800) && !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40500) && !defined(__SUNPRO_CC) - // this condition is a copy paste from is_constructible.hpp - // I also disable SUNPRO, as it seems not to support type_traits correctly +#if !defined(BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT) template struct is_convertible_to_T_or_factory @@ -751,8 +749,6 @@ struct is_optional_constructible : boost::is_constructible #else -#define BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT - template struct is_convertible_to_T_or_factory : boost::true_type {}; @@ -820,8 +816,11 @@ class optional : public optional_detail::optional_base // Requires a valid conversion from U to T. // Can throw if T::T(U const&) does template - explicit optional ( optional const& rhs, - typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0) + explicit optional ( optional const& rhs +#ifdef BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS + ,typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0 +#endif + ) : base() { @@ -834,8 +833,11 @@ class optional : public optional_detail::optional_base // Requires a valid conversion from U to T. // Can throw if T::T(U&&) does template - explicit optional ( optional && rhs, - typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0 ) + explicit optional ( optional && rhs +#ifdef BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS + ,typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0 +#endif + ) : base() { @@ -954,8 +956,7 @@ class optional : public optional_detail::optional_base } #endif - -#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX // Assigns from a T (deep-moves/copies the rhs value) template @@ -965,6 +966,7 @@ class optional : public optional_detail::optional_base this->assign( boost::forward(val) ) ; return *this ; } + #else // Assigns from a T (deep-copies the rhs value) @@ -975,8 +977,17 @@ class optional : public optional_detail::optional_base return *this ; } +#ifndef BOOST_OPTIONAL_DETAIL_NO_RVALUE_REFERENCES + // Assigns from a T (deep-moves the rhs value) + optional& operator= ( rval_reference_type val ) + { + this->assign( boost::move(val) ) ; + return *this ; + } #endif +#endif // BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX + // Assigns from a "none" // Which destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 919ba67..1820ba4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -42,7 +42,7 @@ import testing ; [ run optional_test_emplace.cpp ] [ run optional_test_minimum_requirements.cpp ] [ run optional_test_msvc_bug_workaround.cpp ] - [ compile optional_test_sfinae_friendly_value_ctor.cpp ] + [ compile optional_test_sfinae_friendly_ctor.cpp ] [ compile-fail optional_test_ref_convert_assign_const_int_prevented.cpp ] [ compile-fail optional_test_fail1.cpp ] [ compile-fail optional_test_fail3a.cpp ] diff --git a/test/optional_test_sfinae_friendly_value_ctor.cpp b/test/optional_test_sfinae_friendly_ctor.cpp similarity index 95% rename from test/optional_test_sfinae_friendly_value_ctor.cpp rename to test/optional_test_sfinae_friendly_ctor.cpp index 6c2abda..3fefc0e 100644 --- a/test/optional_test_sfinae_friendly_value_ctor.cpp +++ b/test/optional_test_sfinae_friendly_ctor.cpp @@ -33,6 +33,7 @@ BOOST_STATIC_ASSERT(( !boost::is_constructible::value )); BOOST_STATIC_ASSERT(( boost::is_constructible, const X&>::value )); BOOST_STATIC_ASSERT(( !boost::is_constructible, const Y&>::value )); +#ifdef BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS BOOST_STATIC_ASSERT(( boost::is_constructible< optional< optional >, optional >::value )); BOOST_STATIC_ASSERT(( !boost::is_constructible< optional, optional< optional > >::value )); @@ -41,6 +42,7 @@ BOOST_STATIC_ASSERT(( !boost::is_constructible< optional, const optional< o BOOST_STATIC_ASSERT(( boost::is_constructible, const optional&>::value )); BOOST_STATIC_ASSERT(( !boost::is_constructible, const optional&>::value )); +#endif #endif From d73b5110dd931ba3053360d1743f181a978a8d32 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Tue, 22 Nov 2016 02:35:24 +0100 Subject: [PATCH 4/6] corrected the compiler workarounds --- include/boost/optional/detail/optional_config.hpp | 4 ++-- include/boost/optional/optional.hpp | 4 ++-- test/optional_test_convert_from_T.cpp | 2 ++ test/optional_test_sfinae_friendly_ctor.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/boost/optional/detail/optional_config.hpp b/include/boost/optional/detail/optional_config.hpp index 5c388fb..42aeda0 100644 --- a/include/boost/optional/detail/optional_config.hpp +++ b/include/boost/optional/detail/optional_config.hpp @@ -104,9 +104,9 @@ #endif #if defined __SUNPRO_CC -# define BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS +# define BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS #elif (defined _MSC_FULL_VER) && (_MSC_FULL_VER < 190023026) -# define BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS +# define BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS #endif #endif // header guard diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index e450898..a465b9e 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -817,7 +817,7 @@ class optional : public optional_detail::optional_base // Can throw if T::T(U const&) does template explicit optional ( optional const& rhs -#ifdef BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS +#ifndef BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS ,typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0 #endif ) @@ -834,7 +834,7 @@ class optional : public optional_detail::optional_base // Can throw if T::T(U&&) does template explicit optional ( optional && rhs -#ifdef BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS +#ifndef BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS ,typename boost::enable_if< optional_detail::is_optional_constructible >::type* = 0 #endif ) diff --git a/test/optional_test_convert_from_T.cpp b/test/optional_test_convert_from_T.cpp index 2abe7e5..6d4c2ff 100644 --- a/test/optional_test_convert_from_T.cpp +++ b/test/optional_test_convert_from_T.cpp @@ -41,9 +41,11 @@ struct superconv void test_optional_of_superconverting_T() // compile-time test { +#ifndef BOOST_OPTIONAL_DETAIL_NO_IS_CONSTRUCTIBLE_TRAIT superconv > s; superconv > & rs = s; optional > > os = rs; +#endif } void test_optional_optional_T() diff --git a/test/optional_test_sfinae_friendly_ctor.cpp b/test/optional_test_sfinae_friendly_ctor.cpp index 3fefc0e..87539e1 100644 --- a/test/optional_test_sfinae_friendly_ctor.cpp +++ b/test/optional_test_sfinae_friendly_ctor.cpp @@ -33,7 +33,7 @@ BOOST_STATIC_ASSERT(( !boost::is_constructible::value )); BOOST_STATIC_ASSERT(( boost::is_constructible, const X&>::value )); BOOST_STATIC_ASSERT(( !boost::is_constructible, const Y&>::value )); -#ifdef BOOST_OPTIONAL_DETAIL_USE_SFINAE_FRIENDLY_CONSTRUCTORS +#ifndef BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS BOOST_STATIC_ASSERT(( boost::is_constructible< optional< optional >, optional >::value )); BOOST_STATIC_ASSERT(( !boost::is_constructible< optional, optional< optional > >::value )); From 17826eae3be33381bdf02943e4cb22335012994e Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Thu, 24 Nov 2016 23:20:25 +0100 Subject: [PATCH 5/6] more old compiler workarounds --- include/boost/optional/detail/optional_config.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/optional/detail/optional_config.hpp b/include/boost/optional/detail/optional_config.hpp index 42aeda0..e26d73c 100644 --- a/include/boost/optional/detail/optional_config.hpp +++ b/include/boost/optional/detail/optional_config.hpp @@ -107,6 +107,10 @@ # define BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS #elif (defined _MSC_FULL_VER) && (_MSC_FULL_VER < 190023026) # define BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS +#elif defined BOOST_GCC && !defined BOOST_GCC_CXX11 +# define BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS +#elif defined BOOST_GCC_VERSION && BOOST_GCC_VERSION < 40800 +# define BOOST_OPTIONAL_DETAIL_NO_SFINAE_FRIENDLY_CONSTRUCTORS #endif #endif // header guard From 1618d5f3bb01cbd1cbb666bf3e1cf195fa4f3c08 Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Thu, 24 Nov 2016 23:31:43 +0100 Subject: [PATCH 6/6] release notes --- doc/91_relnotes.qbk | 2 ++ doc/html/boost_optional/relnotes.html | 8 ++++++++ doc/html/index.html | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/91_relnotes.qbk b/doc/91_relnotes.qbk index a026a8b..d9ca103 100644 --- a/doc/91_relnotes.qbk +++ b/doc/91_relnotes.qbk @@ -13,7 +13,9 @@ [heading Boost Release 1.63] * Added two new in-place constructors. They work similarly to `emplace()` functions: they initialize the contained value by perfect-forwarding the obtained arguments. One constructor always initializes the contained value, the other based on a boolean condition. +* Syntax `o = {}` now correctly un-initializes optional, just like in `std::optional`. * Fixed [@https://svn.boost.org/trac/boost/ticket/12203 Trac #12203]. +* Fixed [@https://svn.boost.org/trac/boost/ticket/12563 Trac #12563]. [heading Boost Release 1.62] diff --git a/doc/html/boost_optional/relnotes.html b/doc/html/boost_optional/relnotes.html index 6a6db62..79243a2 100644 --- a/doc/html/boost_optional/relnotes.html +++ b/doc/html/boost_optional/relnotes.html @@ -38,9 +38,17 @@ obtained arguments. One constructor always initializes the contained value, the other based on a boolean condition. +
  • + Syntax o = + {} now correctly un-initializes + optional, just like in std::optional. +
  • Fixed Trac #12203.
  • +
  • + Fixed Trac #12563. +
  • diff --git a/doc/html/index.html b/doc/html/index.html index e2a485d..9c087a2 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -145,7 +145,7 @@ - +

    Last revised: November 06, 2016 at 00:39:48 GMT

    Last revised: November 24, 2016 at 22:27:48 GMT