diff --git a/doc/00_optional.qbk b/doc/00_optional.qbk index 1c8d59b..fcc308a 100644 --- a/doc/00_optional.qbk +++ b/doc/00_optional.qbk @@ -41,6 +41,7 @@ Distributed under the Boost Software License, Version 1.0. [def __SGI_DEFAULT_CONSTRUCTIBLE__ [@http://www.sgi.com/tech/stl/DefaultConstructible.html `DefaultConstructible`]] [def __SGI_LESS_THAN_COMPARABLE__ [@http://www.sgi.com/tech/stl/LessThanComparable.html `LessThanComparable`]] [def __SGI_EQUALITY_COMPARABLE__ [@http://www.sgi.com/tech/stl/EqualityComparable.html `EqualityComparable`]] +[def __SGI_GENERATOR__ [@http://www.sgi.com/tech/stl/Generator.html `Generator`]] [/ Icons ] diff --git a/doc/01_quick_start.qbk b/doc/01_quick_start.qbk index 10d55e6..71053e1 100644 --- a/doc/01_quick_start.qbk +++ b/doc/01_quick_start.qbk @@ -48,7 +48,16 @@ This version throws an exception upon an attempt to access a non-existent contai int k = convert(text).value_or(0); -This uses the `atoi`-like approach to conversions: if `text` does not represent an integral number just return `0`. Now, let's consider how function `convert` can be implemented. +This uses the `atoi`-like approach to conversions: if `text` does not represent an integral number just return `0`. Finally, you can provide a callback to be called when trying to access the contained value fails: + + int l = convert(text).value_or_eval([]() -> int { + cout << "could not convert; using -1 instead" << endl; + return -1; + }); + +This will call the provided callback and return whatever the callback returns. The callback can have side effects: they will only be observed when the optional object does not contain a value. + +Now, let's consider how function `convert` can be implemented. boost::optionl convert(const std::string& text) { diff --git a/doc/20_reference.qbk b/doc/20_reference.qbk index 3a6330e..fea6a37 100644 --- a/doc/20_reference.qbk +++ b/doc/20_reference.qbk @@ -73,14 +73,17 @@ T const& operator *() const& ; ``[link reference_optional_operator_asterisk __GO_TO__]`` T& operator *() &; ``[link reference_optional_operator_asterisk __GO_TO__]`` - T&& operator *() &&; ``[link reference_optional_operator_asterisk __GO_TO__]`` + T operator *() &&; ``[link reference_optional_operator_asterisk_move __GO_TO__]`` T const& value() const& ; ``[link reference_optional_value __GO_TO__]`` T& value() & ; ``[link reference_optional_value __GO_TO__]`` - T&& value() && ; ``[link reference_optional_value __GO_TO__]`` + T value() && ; ``[link reference_optional_value_move __GO_TO__]`` template T value_or( U && v ) const& ; ``[link reference_optional_value_or __GO_TO__]`` template T value_or( U && v ) && ; ``[link reference_optional_value_or_move __GO_TO__]`` + + template T value_or_eval( F f ) const& ; ``[link reference_optional_value_or_call __GO_TO__]`` + template T value_or_eval( F f ) && ; ``[link reference_optional_value_or_call_move __GO_TO__]`` T const* get_ptr() const ; ``[link reference_optional_get_ptr __GO_TO__]`` T* get_ptr() ; ``[link reference_optional_get_ptr __GO_TO__]`` @@ -442,7 +445,7 @@ __SPACE__ * [*Effect:] Move-constructs an `optional`. * [*Postconditions:] If `rhs` is initialized, `*this` is initialized and its -value is move constructed from `*rhs`; else `*this` is +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 @@ -837,12 +840,11 @@ __SPACE__ [: `T const& optional::operator*() const& ;`] [: `T& optional::operator*() &;`] -[: `T&& optional::operator*() &&;`] * [*Requires:] `*this` is initialized * [*Returns:] A reference to the contained value * [*Throws:] Nothing. -* [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. On compilers that do not support ref-qualifiers on member functions these three overloads are replaced with the classical two: a `const` and non-`const` member functions. +* [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. On compilers that do not support ref-qualifiers on member functions these two overloads are replaced with the classical two: a `const` and non-`const` member functions. * [*Example:] `` T v ; @@ -856,6 +858,17 @@ assert ( *opt == w ) ; __SPACE__ +[#reference_optional_operator_asterisk_move] + +[: `T optional::operator*() &&;`] + +* [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__ and `*this` is initialized. +* [*Returns:] A move-constructed copy the contained value. +* [*Throws:] Whatever the `T`'s constructor selected for the move throws. +* [*Notes:] The requirement is asserted via `BOOST_ASSERT()`. On compilers that do not support ref-qualifiers on member functions this overload is not present. + +__SPACE__ + [: `T const& optional::operator*() const& ;`] [: `T & optional::operator*() & ;`] [: `T & optional::operator*() && ;`] @@ -881,11 +894,10 @@ __SPACE__ [: `T const& optional::value() const& ;`] [: `T& optional::value() & ;`] -[: `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. -* [*Notes:] On compilers that do not support ref-qualifiers on member functions these three overloads are replaced with the classical two: a `const` and non-`const` member functions. +* [*Notes:] On compilers that do not support ref-qualifiers on member functions these two overloads are replaced with the classical two: a `const` and non-`const` member functions. * [*Example:] `` T v ; @@ -900,6 +912,18 @@ catch(bad_optional_access&) { assert ( true ); } `` + +__SPACE__ + +[#reference_optional_value_move] + +[: `T optional::value() && ;`] + +* [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__. +* [*Returns:] A move-constructed copy of the contained value, if `*this` is initialized. +* [*Throws:] An instance of `bad_optional_access`, if `*this` is not initialized. +* [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is not present. + __SPACE__ @@ -908,7 +932,7 @@ __SPACE__ [: `template T optional::value_or(U && v) const& ;`] * [*Requires:] `T` is __COPY_CONSTRUCTIBLE__ and `U &&` is convertible to `T`. -* [*Returns:] `bool(*this) ? **this : static_cast(forward(v))`. +* [*Returns:] `bool(*this) ? **this : static_cast(std::forward(v))`. * [*Throws:] Any exception thrown by the selected constructor of `T`. * [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is replaced with the `const`-qualified member function. On compilers without rvalue reference support the type of `v` becomes `U const&`. @@ -919,9 +943,48 @@ __SPACE__ [: `template T optional::value_or(U && v) && ;`] * [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__ and `U &&` is convertible to `T`. -* [*Returns:] `bool(*this) ? std::move(**this) : static_cast(forward(v))`. +* [*Returns:] `bool(*this) ? std::move(**this) : static_cast(std::forward(v))`. * [*Throws:] Any exception thrown by the selected constructor of `T`. -* [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is replaced with the classical non-`const`-qualified member function. On compilers without rvalue reference support the type of `v` becomes `U const&`. +* [*Notes:] On compilers that do not support ref-qualifiers on member functions this overload is not present. + +__SPACE__ + +[#reference_optional_value_or_call] + +[: `template T optional::value_or_eval(F f) const& ;`] + +* [*Requires:] `T` is __COPY_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`. +* [*Returns:] `bool(*this) ? **this : static_cast(f())`. +* [*Throws:] Any exception thrown by the selected constructor of `T` or by `f`. +* [*Notes:] Function `f` is only evaluated if `bool(*this) == false`. On compilers that do not support ref-qualifiers on member functions this overload is replaced with the `const`-qualified member function. +* [*Example:] +`` +int complain_and_0() +{ + clog << "no value returned, using default" << endl; + return 0; +} + +optional o1 = 1; +optional oN = none; + +int i = o1.value_or_eval(complain_and_0); // fun not called +assert (i == 1); + +int j = oN.value_or_eval(complain_and_0); // fun called +assert (i == 0); +`` + +__SPACE__ + +[#reference_optional_value_or_call_move] + +[: `template T optional::value_or_eval(F f) && ;`] + +* [*Requires:] `T` is __MOVE_CONSTRUCTIBLE__ and `F` models a __SGI_GENERATOR__ whose result type is convertible to `T`. +* [*Returns:] `bool(*this) ? std::move(**this) : static_cast(f())`. +* [*Throws:] Any exception thrown by the selected constructor of `T` or by `f`. +* [*Notes:] Function `f` is only evaluated if `bool(*this) == false`. On compilers that do not support ref-qualifiers on member functions this overload is not present. __SPACE__ diff --git a/doc/91_acknowledgments.qbk b/doc/91_acknowledgments.qbk index 117a468..cb1b3bb 100644 --- a/doc/91_acknowledgments.qbk +++ b/doc/91_acknowledgments.qbk @@ -9,7 +9,7 @@ ] -[section Acknowledgments] +[section Acknowledgements] [heading Pre-formal review] @@ -55,6 +55,8 @@ Rob Stewart, and others. with the proper semantics. * Mat Marcus shown the virtues of a value-oriented interface, influencing the current design, and contributed the idea of "none". +* Vladimir Batov's design of Boost.Convert library motivated the development +of value accessors for `optional`: functions `value`, `value_or`, `value_or_eval`. [endsect] diff --git a/doc/html/boost_optional/acknowledgements.html b/doc/html/boost_optional/acknowledgements.html new file mode 100644 index 0000000..659795d --- /dev/null +++ b/doc/html/boost_optional/acknowledgements.html @@ -0,0 +1,130 @@ + + + +Acknowledgements + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHome +
+
+ +

+ + Pre-formal + review +

+
    +
  • + Peter Dimov suggested the name 'optional', and was the first to point out + the need for aligned storage. +
  • +
  • + Douglas Gregor developed 'type_with_alignment', and later Eric Friedman + coded 'aligned_storage', which are the core of the optional class implementation. +
  • +
  • + Andrei Alexandrescu and Brian Parker also worked with aligned storage techniques + and their work influenced the current implementation. +
  • +
  • + Gennadiy Rozental made extensive and important comments which shaped the + design. +
  • +
  • + Vesa Karvonen and Douglas Gregor made quite useful comparisons between + optional, variant and any; and made other relevant comments. +
  • +
  • + Douglas Gregor and Peter Dimov commented on comparisons and evaluation + in boolean contexts. +
  • +
  • + Eric Friedman helped understand the issues involved with aligned storage, + move/copy operations and exception safety. +
  • +
  • + Many others have participated with useful comments: Aleksey Gurotov, Kevlin + Henney, David Abrahams, and others I can't recall. +
  • +
+

+ + Post-formal + review +

+
    +
  • + William Kempf carefully considered the originally proposed interface and + suggested the new interface which is currently used. He also started and + fueled the discussion about the analogy optional<>/smart pointer + and about relational operators. +
  • +
  • + Peter Dimov, Joel de Guzman, David Abrahams, Tanton Gibbs and Ian Hanson + focused on the relational semantics of optional (originally undefined); + concluding with the fact that the pointer-like interface doesn't make it + a pointer so it shall have deep relational operators. +
  • +
  • + Augustus Saunders also explored the different relational semantics between + optional<> and a pointer and developed the OptionalPointee concept + as an aid against potential conflicts on generic code. +
  • +
  • + Joel de Guzman noticed that optional<> can be seen as an API on top + of variant<T,nil_t>. +
  • +
  • + Dave Gomboc explained the meaning and usage of the Haskell analog to optional<>: + the Maybe type constructor (analogy originally pointed out by David Sankel). +
  • +
  • + Other comments were posted by Vincent Finn, Anthony Williams, Ed Brey, + Rob Stewart, and others. +
  • +
  • + Joel de Guzman made the case for the support of references and helped with + the proper semantics. +
  • +
  • + Mat Marcus shown the virtues of a value-oriented interface, influencing + the current design, and contributed the idea of "none". +
  • +
  • + Vladimir Batov's design of Boost.Convert library motivated the development + of value accessors for optional: + functions value, value_or, value_or_eval. +
  • +
+
+ + + +
+
+
+PrevUpHome +
+ + diff --git a/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html b/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html index 991a0cf..b27d9c1 100644 --- a/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html +++ b/doc/html/boost_optional/dependencies_and_portability/optional_reference_binding.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -94,7 +94,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_optional/quick_start.html b/doc/html/boost_optional/quick_start.html index e8cc11b..adee769 100644 --- a/doc/html/boost_optional/quick_start.html +++ b/doc/html/boost_optional/quick_start.html @@ -111,6 +111,20 @@ This uses the atoi-like approach to conversions: if text does not represent an integral number just return 0. + Finally, you can provide a callback to be called when trying to access the + contained value fails: +

+
int l = convert(text).value_or_eval([]() -> int {
+  cout << "could not convert; using -1 instead" << endl;
+  return -1;
+});
+
+

+ This will call the provided callback and return whatever the callback returns. + The callback can have side effects: they will only be observed when the optional + object does not contain a value. +

+

Now, let's consider how function convert can be implemented.

diff --git a/doc/html/boost_optional/reference/detailed_semantics.html b/doc/html/boost_optional/reference/detailed_semantics.html index 23c6745..78e75c8 100644 --- a/doc/html/boost_optional/reference/detailed_semantics.html +++ b/doc/html/boost_optional/reference/detailed_semantics.html @@ -541,7 +541,7 @@
  • Postconditions: If rhs is initialized, *this - is initialized and its value is move constructed from *rhs; else *this is uninitialized. + is initialized and its value is move-constructed from *rhs; else *this is uninitialized.
  • Throws: Whatever T::T( U&& ) @@ -1269,10 +1269,6 @@ T& optional<T (not a ref)>::operator*() &;

  • -

    - T&& - optional<T (not a ref)>::operator*() &&; -

    • Requires: *this is initialized @@ -1288,8 +1284,8 @@ Notes: The requirement is asserted via BOOST_ASSERT(). On compilers that do not support ref-qualifiers on member functions these - three overloads are replaced with the classical two: a const and non-const - member functions. + two overloads are replaced with the classical two: a const + and non-const member functions.
    • Example: @@ -1303,6 +1299,35 @@
    +

    + space +

    +

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

    +
      +
    • + Requires: T + is MoveConstructible + and *this + is initialized. +
    • +
    • + Returns: A move-constructed copy the + contained value. +
    • +
    • + Throws: Whatever the T's + constructor selected for the move throws. +
    • +
    • + Notes: The requirement is asserted via + BOOST_ASSERT(). + On compilers that do not support ref-qualifiers on member functions this + overload is not present. +
    • +

    space

    @@ -1357,10 +1382,6 @@ T& optional<T>::value() & ;

    -

    - T&& - optional<T>::value() && ; -

    • Returns: A reference to the contained @@ -1373,8 +1394,8 @@
    • Notes: On compilers that do not support - ref-qualifiers on member functions these three overloads are replaced - with the classical two: a const + ref-qualifiers on member functions these two overloads are replaced with + the classical two: a const and non-const member functions.
    • @@ -1391,9 +1412,36 @@ assert ( true ); } - space
    +

    + space +

    +

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

    +
      +
    • + Requires: T + is MoveConstructible. +
    • +
    • + Returns: A move-constructed copy of + the contained value, if *this is initialized. +
    • +
    • + Throws: An instance of bad_optional_access, if *this + is not initialized. +
    • +
    • + Notes: On compilers that do not support + ref-qualifiers on member functions this overload is not present. +
    • +
    +

    + space +

    template<class U> T optional<T>::value_or(U && v) @@ -1407,7 +1455,7 @@ is convertible to T.

  • - Returns: bool(*this) ? **this : static_cast<T>(forward<U>(v)). + Returns: bool(*this) ? **this : static_cast<T>(std::forward<U>(v)).
  • Throws: Any exception thrown by the @@ -1437,7 +1485,7 @@ is convertible to T.
  • - Returns: bool(*this) ? std::move(**this) : static_cast<T>(forward<U>(v)). + Returns: bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v)).
  • Throws: Any exception thrown by the @@ -1445,10 +1493,79 @@
  • Notes: On compilers that do not support + ref-qualifiers on member functions this overload is not present. +
  • +
    +

    + space +

    +

    + template<class F> T optional<T>::value_or_eval(F f) const& ; +

    +
      +
    • + Requires: T + is CopyConstructible and F models a Generator whose result type + is convertible to T. +
    • +
    • + Returns: bool(*this) ? **this : static_cast<T>(f()). +
    • +
    • + Throws: Any exception thrown by the + selected constructor of T + or by f. +
    • +
    • + Notes: Function f + is only evaluated if bool(*this) == false. On compilers that do not support ref-qualifiers on member functions this overload is replaced with the - classical non-const-qualified - member function. On compilers without rvalue reference support the type - of v becomes U const&. + const-qualified member function. +
    • +
    • + Example: +
      int complain_and_0()
      +{
      +  clog << "no value returned, using default" << endl;
      +  return 0;
      +}
      +
      +optional<int> o1 = 1;
      +optional<int> oN = none;
      +
      +int i = o1.value_or_eval(complain_and_0); // fun not called
      +assert (i == 1);
      +
      +int j = oN.value_or_eval(complain_and_0); // fun called
      +assert (i == 0);
      +
      +
    • +
    +

    + space +

    +

    + template<class F> T optional<T>::value_or_eval(F f) && ; +

    +
      +
    • + Requires: T + is MoveConstructible + and F models a Generator + whose result type is convertible to T. +
    • +
    • + Returns: bool(*this) ? std::move(**this) : static_cast<T>(f()). +
    • +
    • + Throws: Any exception thrown by the + selected constructor of T + or by f. +
    • +
    • + Notes: Function f + is only evaluated if bool(*this) == false. On compilers that do not support + ref-qualifiers on member functions this overload is not present.

    diff --git a/doc/html/index.html b/doc/html/index.html index a96a8b8..b1c713c 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -84,7 +84,7 @@

    Optional Reference Binding
    -
    Acknowledgments
    +
    Acknowledgements
    @@ -133,7 +133,7 @@
    - +

    Last revised: June 16, 2014 at 12:04:51 GMT

    Last revised: June 18, 2014 at 14:36:35 GMT


    diff --git a/doc/html/optional/reference.html b/doc/html/optional/reference.html index 0ab1183..dc2dd88 100644 --- a/doc/html/optional/reference.html +++ b/doc/html/optional/reference.html @@ -97,15 +97,18 @@ T const& operator *() const& ; R T& operator *() &; R - T&& operator *() &&; R + T operator *() &&; R T const& value() const& ; R T& value() & ; R - T&& value() && ; R + T value() && ; R template<class U> T value_or( U && v ) const& ; R template<class U> T value_or( U && v ) && ; R + template<class F> T value_or_eval( F f ) const& ; R + template<class F> T value_or_eval( F f ) && ; R + T const* get_ptr() const ; R T* get_ptr() ; R diff --git a/include/boost/optional/optional.hpp b/include/boost/optional/optional.hpp index 35e147c..8e3a5dd 100644 --- a/include/boost/optional/optional.hpp +++ b/include/boost/optional/optional.hpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,6 @@ #include #include #include - #include #include @@ -115,6 +113,27 @@ template void swap ( optional& x, optional& y ); namespace optional_detail { +// converts type U to type T using only implicit conversions/constructors +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + TT convert(UU && u) + { + return forward(u); + } +#else + template + TT convert(const UU& u) + { + return u; + } + + template + TT convert(UU& u) + { + return u; + } +#endif + // This local class is used instead of that in "aligned_storage.hpp" // because I've found the 'official' class to ICE BCB5.5 // when some types are used with optional<> @@ -1010,7 +1029,7 @@ class optional : public optional_detail::optional_base #ifndef BOOST_NO_CXX11_REF_QUALIFIERS reference_const_type operator *() const& { return this->get() ; } reference_type operator *() & { return this->get() ; } - reference_type_of_temporary_wrapper operator *() && { return boost::move(this->get()) ; } + value_type operator *() && { return boost::move(this->get()) ; } #else reference_const_type operator *() const { return this->get() ; } reference_type operator *() { return this->get() ; } @@ -1033,7 +1052,7 @@ class optional : public optional_detail::optional_base throw_exception(bad_optional_access("Attempted to access the value of an uninitialized optional object.")); } - reference_type_of_temporary_wrapper value() && + value_type value() && { if (this->is_initialized()) return boost::move(this->get()) ; @@ -1058,33 +1077,51 @@ class optional : public optional_detail::optional_base } #endif + #ifndef BOOST_NO_CXX11_REF_QUALIFIERS template value_type value_or ( U&& v ) const& { - BOOST_STATIC_ASSERT((is_convertible::value)); - return this->is_initialized() ? get() : static_cast(boost::forward(v)); + return this->is_initialized() ? get() : optional_detail::convert(boost::forward(v)); } template value_type value_or ( U&& v ) && { - BOOST_STATIC_ASSERT((is_convertible::value)); - return this->is_initialized() ? boost::move(get()) : static_cast(boost::forward(v)); + return this->is_initialized() ? boost::move(get()) : optional_detail::convert(boost::forward(v)); } #elif !defined BOOST_NO_CXX11_RVALUE_REFERENCES template value_type value_or ( U&& v ) const { - BOOST_STATIC_ASSERT((is_convertible::value)); - return this->is_initialized() ? get() : static_cast(boost::forward(v)); + return this->is_initialized() ? get() : optional_detail::convert(boost::forward(v)); } #else template value_type value_or ( U const& v ) const { - BOOST_STATIC_ASSERT((is_convertible::value)); - return this->is_initialized() ? get() : static_cast(v); + return this->is_initialized() ? get() : optional_detail::convert(v); + } +#endif + + +#ifndef BOOST_NO_CXX11_REF_QUALIFIERS + template + value_type value_or_eval ( F f ) const& + { + return this->is_initialized() ? get() : optional_detail::convert(f()); + } + + template + value_type value_or_eval ( F f ) && + { + return this->is_initialized() ? boost::move(get()) : optional_detail::convert(f()); + } +#else + template + value_type value_or_eval ( F f ) const + { + return this->is_initialized() ? get() : optional_detail::convert(f()); } #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 04c6cd4..aeb0900 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -42,5 +42,6 @@ import testing ; [ compile-fail optional_test_ref_fail_assign_from_Trefref.cpp ] [ compile-fail optional_test_ref_fail_assign_from_Urefref.cpp ] [ compile-fail optional_test_fail_explicit_convert_in_value_or.cpp ] + [ compile-fail optional_test_fail_explicit_convert_in_value_or_call.cpp ] ; } diff --git a/test/optional_test_fail_explicit_convert_in_value_or_call.cpp b/test/optional_test_fail_explicit_convert_in_value_or_call.cpp new file mode 100644 index 0000000..e37d235 --- /dev/null +++ b/test/optional_test_fail_explicit_convert_in_value_or_call.cpp @@ -0,0 +1,34 @@ +// 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 +// + +struct U +{}; + +struct T +{ + explicit T(U const&) {} +}; + +U get_U() { return U(); } + + +void test_verifying_the_implicit_conversion_to_bool() +{ + boost::optional opt; + opt.value_or_eval(get_U); +} + diff --git a/test/optional_test_value_access.cpp b/test/optional_test_value_access.cpp index 506278f..bc4ed4a 100644 --- a/test/optional_test_value_access.cpp +++ b/test/optional_test_value_access.cpp @@ -128,6 +128,73 @@ void test_function_value_or() BOOST_CHECK(FatToIntConverter::conversions == 1); } + +struct FunM +{ + int operator()() { return 5; } +}; + +struct FunC +{ + int operator()() const { return 6; } +}; + +int funP () +{ + return 7; +} + +int throw_() +{ + throw int(); +} + +void test_function_value_or_call() +{ + optional o1 = 1; + optional oN; + FunM funM; + FunC funC; + + BOOST_CHECK(o1.value_or_eval(funM) == 1); + BOOST_CHECK(oN.value_or_eval(funM) == 5); + BOOST_CHECK(o1.value_or_eval(FunM()) == 1); + BOOST_CHECK(oN.value_or_eval(FunM()) == 5); + + BOOST_CHECK(o1.value_or_eval(funC) == 1); + BOOST_CHECK(oN.value_or_eval(funC) == 6); + BOOST_CHECK(o1.value_or_eval(FunC()) == 1); + BOOST_CHECK(oN.value_or_eval(FunC()) == 6); + + BOOST_CHECK(o1.value_or_eval(funP) == 1); + BOOST_CHECK(oN.value_or_eval(funP) == 7); + +#ifndef BOOST_NO_CXX11_LAMBDAS + BOOST_CHECK(o1.value_or_eval([](){return 8;}) == 1); + BOOST_CHECK(oN.value_or_eval([](){return 8;}) == 8); +#endif + + try + { + BOOST_CHECK(o1.value_or_eval(throw_) == 1); + } + catch(...) + { + BOOST_CHECK(false); + } + + try + { + BOOST_CHECK(oN.value_or_eval(throw_) == 1); + BOOST_CHECK(false); + } + catch(...) + { + BOOST_CHECK(true); + } +} + + #ifndef BOOST_NO_CXX11_REF_QUALIFIERS struct MoveOnly { @@ -144,15 +211,22 @@ optional makeMoveOnly() return MoveOnly(1); } +MoveOnly moveOnlyDefault() +{ + return MoveOnly(1); +} + // compile-time test void test_move_only_getters() { MoveOnly m1 = *makeMoveOnly(); MoveOnly m2 = makeMoveOnly().value(); MoveOnly m3 = makeMoveOnly().value_or(MoveOnly(1)); + MoveOnly m4 = makeMoveOnly().value_or_eval(moveOnlyDefault); unused_variable(m1); unused_variable(m2); unused_variable(m3); + unused_variable(m4); } #endif @@ -163,6 +237,7 @@ int test_main( int, char* [] ) { test_function_value(); test_function_value_or(); + test_function_value_or_call(); } catch ( ... ) {