From 75271b73a8484cb5add003f65f1432c05c47dc8b Mon Sep 17 00:00:00 2001
From: Andrzej Krzemienski
Date: Thu, 22 May 2014 23:32:49 +0200
Subject: [PATCH] Member fun value() that throws on uninitialized
---
.../boost_optional/detailed_semantics.html | 37 ++++++
.../exception_safety_guarantees.html | 4 +-
doc/html/boost_optional/synopsis.html | 3 +
doc/html/index.html | 2 +-
doc/reference.qbk | 28 +++++
doc/special_cases.qbk | 2 +-
include/boost/bad_optional_access.hpp | 28 +++++
include/boost/optional/optional.hpp | 18 +++
include/boost/optional/optional_fwd.hpp | 2 -
test/Jamfile.v2 | 1 +
test/optional_test_value_access.cpp | 107 ++++++++++++++++++
11 files changed, 226 insertions(+), 6 deletions(-)
create mode 100644 include/boost/bad_optional_access.hpp
create mode 100644 test/optional_test_value_access.cpp
diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html
index 4a5394e..dbfe0cb 100644
--- a/doc/html/boost_optional/detailed_semantics.html
+++ b/doc/html/boost_optional/detailed_semantics.html
@@ -1200,6 +1200,43 @@
+
+
+
+
+ T const& optional<T>::value() const ;
+
+
+ T&
+ optional<T>::value();
+
+
diff --git a/doc/html/boost_optional/exception_safety_guarantees.html b/doc/html/boost_optional/exception_safety_guarantees.html
index eb29f92..4b2b0a5 100644
--- a/doc/html/boost_optional/exception_safety_guarantees.html
+++ b/doc/html/boost_optional/exception_safety_guarantees.html
@@ -95,8 +95,8 @@
Unless T
's constructor or assignment
- throws, optional<T>
does
- not throw anything else on its own. A throw during assignment never changes
+ throws, assignments to optional<T>
+ do not throw anything else on its own. A throw during assignment never changes
the initialization state of any optional object involved:
optional<T> opt1(val1);
diff --git a/doc/html/boost_optional/synopsis.html b/doc/html/boost_optional/synopsis.html
index 075bfbf..0e2b20e 100644
--- a/doc/html/boost_optional/synopsis.html
+++ b/doc/html/boost_optional/synopsis.html
@@ -90,6 +90,9 @@
T const& operator *() const ;
T& operator *() ;
+ T const& value() const ;
+ T& value() ;
+
T const* get_ptr() const ;
T* get_ptr() ;
diff --git a/doc/html/index.html b/doc/html/index.html
index 1bb9006..5c74f5b 100644
--- a/doc/html/index.html
+++ b/doc/html/index.html
@@ -92,7 +92,7 @@
-Last revised: May 08, 2014 at 12:05:10 GMT |
+Last revised: May 22, 2014 at 21:28:38 GMT |
|
diff --git a/doc/reference.qbk b/doc/reference.qbk
index 5cbaf6b..80c6927 100644
--- a/doc/reference.qbk
+++ b/doc/reference.qbk
@@ -74,6 +74,9 @@
T const& operator *() const ; ``[link reference_optional_get __GO_TO__]``
T& operator *() ; ``[link reference_optional_get __GO_TO__]``
+
+ T const& value() const ; ``[link reference_optional_value __GO_TO__]``
+ T& value() ; ``[link reference_optional_value __GO_TO__]``
T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]``
T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]``
@@ -803,6 +806,31 @@ assert ( *opt == w ) ;
__SPACE__
+
+[#reference_optional_value]
+
+[: `T const& optional::value() const ;`]
+[: `T& optional::value();`]
+
+* [*Returns:] A reference to the contained value, if `*this` is initialized.
+* [*Throws:] An instance of `bad_optional_access`, if `*this` is not initialized.
+* [*Example:]
+``
+T v ;
+optional o0, o1 ( v );
+assert ( o1.value() == v );
+
+try {
+ o0.value(); // throws
+ assert ( false );
+}
+catch(bad_optional_access&) {
+ asert ( true );
+}
+``
+
+__SPACE__
+
[#reference_optional_get_value_or_value]
[: `T const& optional::get_value_or( T const& default) const ;`]
diff --git a/doc/special_cases.qbk b/doc/special_cases.qbk
index adc191e..6173c16 100644
--- a/doc/special_cases.qbk
+++ b/doc/special_cases.qbk
@@ -336,7 +336,7 @@ Regarding the following assignment functions:
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.
-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:
+Unless `T`'s constructor or assignment throws, assignments to `optional` do not throw anything else on its own. A throw during assignment never changes the initialization state of any optional object involved:
optional opt1(val1);
diff --git a/include/boost/bad_optional_access.hpp b/include/boost/bad_optional_access.hpp
new file mode 100644
index 0000000..95abf3a
--- /dev/null
+++ b/include/boost/bad_optional_access.hpp
@@ -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/libs/optional for documentation.
+//
+// You are welcome to contact the author at:
+// akrzemi1@gmail.com
+//
+#ifndef BOOST_BAD_OPTIONAL_ACCESS_22MAY2014_HPP
+#define BOOST_BAD_OPTIONAL_ACCESS_22MAY2014_HPP
+
+#include
+
+namespace boost {
+
+class bad_optional_access : public std::logic_error
+{
+public:
+ explicit bad_optional_access(const std::string& what_arg) : std::logic_error(what_arg) {}
+ explicit bad_optional_access(const char* what_arg) : std::logic_error(what_arg) {}
+};
+
+} // namespace boost
+
+#endif
diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp
index d9e8a97..b6ca7e9 100644
--- a/include/boost/optional/optional.hpp
+++ b/include/boost/optional/optional.hpp
@@ -23,7 +23,9 @@
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -935,6 +937,22 @@ class optional : public optional_detail::optional_base
// No-throw
reference_const_type operator *() const { return this->get() ; }
reference_type operator *() { return this->get() ; }
+
+ reference_const_type value() const
+ {
+ if (this->is_initialized())
+ return this->get() ;
+ else
+ throw_exception(bad_optional_access("Attempted to access the value of an uninitialized optional object."));
+ }
+
+ reference_type value()
+ {
+ if (this->is_initialized())
+ return this->get() ;
+ else
+ throw_exception(bad_optional_access("Attempted to access the value of an uninitialized optional object."));
+ }
bool operator!() const BOOST_NOEXCEPT { return !this->is_initialized() ; }
diff --git a/include/boost/optional/optional_fwd.hpp b/include/boost/optional/optional_fwd.hpp
index 29cee49..fb59682 100644
--- a/include/boost/optional/optional_fwd.hpp
+++ b/include/boost/optional/optional_fwd.hpp
@@ -11,11 +11,9 @@
//
// 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
namespace boost {
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 7218ffa..10fd597 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_value_access.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_value_access.cpp b/test/optional_test_value_access.cpp
new file mode 100644
index 0000000..5cff1b7
--- /dev/null
+++ b/test/optional_test_value_access.cpp
@@ -0,0 +1,107 @@
+// 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 IntWrapper
+{
+ int _i;
+ IntWrapper(int i) : _i(i) {}
+ bool operator==(IntWrapper const& rhs) const { return _i == rhs._i; }
+};
+
+template
+void test_function_value_for()
+{
+ optional o0;
+ optional o1(1);
+ const optional oC(2);
+
+ try
+ {
+ T& v = o1.value();
+ BOOST_CHECK(v == 1);
+ }
+ catch(...)
+ {
+ BOOST_CHECK(false);
+ }
+
+ try
+ {
+ T const& v = oC.value();
+ BOOST_CHECK(v == 2);
+ }
+ catch(...)
+ {
+ BOOST_CHECK(false);
+ }
+
+ try
+ {
+ T& v = o0.value();
+ BOOST_CHECK(false);
+ unused_variable(v);
+ }
+ catch(boost::bad_optional_access const&)
+ {
+ }
+ catch(...)
+ {
+ BOOST_CHECK(false);
+ }
+}
+
+void test_function_value()
+{
+ test_function_value_for();
+ test_function_value_for();
+ test_function_value_for();
+}
+
+int test_main( int, char* [] )
+{
+ try
+ {
+ test_function_value();
+
+ }
+ catch ( ... )
+ {
+ BOOST_ERROR("Unexpected Exception caught!");
+ }
+
+ return 0;
+}
+
+