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 @@
- 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 ;
T* get_ptr() ;
- operator unspecified-bool-type() const ;
+ explicit operator bool() const ;
bool operator!() const ;
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