From c7cf80e5df873e11dab3f6bf01c897c9bb661d7b Mon Sep 17 00:00:00 2001 From: Marcel Raad Date: Thu, 24 Apr 2014 10:00:43 +0200 Subject: [PATCH] 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