diff --git a/README.md b/README.md new file mode 100644 index 0000000..4f73388 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +optional +======== + +A library for representing optional (nullable) objects in C++. + +```cpp +optional readInt(); // this function may return either an int or a not-an-int + +if (optional oi = readInt()) // did I get a real int + cout << "my int is: " << *oi; // use my int +else + cout << "I have no int"; +``` + +For more information refer to the documentation provided with this library. diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 93998d0..95de749 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -10,6 +10,7 @@ # Quickbook # ----------------------------------------------------------------------------- +using boostbook ; import quickbook ; path-constant images : html ; @@ -24,7 +25,6 @@ boostbook standalone optional : boost.root=../../../.. - html.stylesheet=boostbook.css toc.max.depth=2 toc.section.depth=2 chunk.section.depth=1 diff --git a/doc/dependencies.qbk b/doc/dependencies.qbk index 6aa0eb5..fce4ca8 100644 --- a/doc/dependencies.qbk +++ b/doc/dependencies.qbk @@ -14,4 +14,54 @@ The implementation uses `type_traits/alignment_of.hpp` and `type_traits/type_with_alignment.hpp` +[section Optional Reference Binding] + +On compilers that do not conform to Standard C++ rules of reference binding, operations on optional references might give adverse results: rather than binding a reference to a designated object they may create an unexpected temporary and bind to it. Compilers known to have these deficiencies include GCC versions 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, 11.0, 12.0. On these compilers prefer using direct-initialization and copy assignment of optional references to copy-initialization and assignment from `T&`: + + const int i = 0; + optional or1; + optional or2 = i; // not portable + or1 = i; // not portable + + optional or3(i); // portable + or1 = optional(i); // portable + +In order to check if your compiler correctly implements reference binding use this test program. + + #include + + const int global_i = 0; + + struct TestingReferenceBinding + { + TestingReferenceBinding(const int& ii) + { + assert(&ii == &global_i); + } + + void operator=(const int& ii) + { + assert(&ii == &global_i); + } + + void operator=(int&&) // remove this if your compiler doesn't have rvalue refs + { + assert(false); + } + }; + + int main() + { + const int& iref = global_i; + assert(&iref == &global_i); + + TestingReferenceBinding ttt = global_i; + ttt = global_i; + + TestingReferenceBinding ttt2 = iref; + ttt2 = iref; + } + +[endsect] + [endsect] \ No newline at end of file diff --git a/doc/html/HTML.manifest b/doc/html/HTML.manifest deleted file mode 100644 index 759b268..0000000 --- a/doc/html/HTML.manifest +++ /dev/null @@ -1,14 +0,0 @@ -index.html -boost_optional/development.html -boost_optional/synopsis.html -boost_optional/detailed_semantics.html -boost_optional/examples.html -boost_optional/optional_references.html -boost_optional/rebinding_semantics_for_assignment_of_optional_references.html -boost_optional/in_place_factories.html -boost_optional/a_note_about_optional_bool_.html -boost_optional/exception_safety_guarantees.html -boost_optional/type_requirements.html -boost_optional/implementation_notes.html -boost_optional/dependencies_and_portability.html -boost_optional/acknowledgments.html diff --git a/doc/html/boost_optional/a_note_about_optional_bool_.html b/doc/html/boost_optional/a_note_about_optional_bool_.html index 8d70d49..169813c 100644 --- a/doc/html/boost_optional/a_note_about_optional_bool_.html +++ b/doc/html/boost_optional/a_note_about_optional_bool_.html @@ -2,8 +2,8 @@ A note about optional<bool> - - + + @@ -32,7 +32,7 @@ be used with special caution and consideration.

- First, it is functionally similar to a tristate boolean (false,maybe,true) + First, it is functionally similar to a tristate boolean (false, maybe, true) —such as boost::tribool— except that in a tristate boolean, the maybe state represents a valid value, unlike the corresponding state of an uninitialized @@ -42,10 +42,11 @@ needed.

- Second, optional<> - provides an implicit conversion to bool. - This conversion refers to the initialization state and not to the contained - value. Using optional<bool> can + Second, although optional<> + provides a contextual conversion to bool + in C++11, this falls back to an implicit conversion on older compilers. This + conversion refers to the initialization state and not to the contained value. + Using optional<bool> can lead to subtle errors due to the implicit bool conversion:

@@ -67,10 +68,33 @@ takes an int instead, it won't compile).

+

+ Third, mixed comparisons with bool + work differently than similar mixed comparisons between pointers and bool, so the results might surprise you: +

+
optional<bool> oEmpty(none), oTrue(true), oFalse(false);
+
+if (oEmpty == none);  // renders true
+if (oEmpty == false); // renders false!
+if (oEmpty == true);  // renders false!
+
+if (oFalse == none);  // renders false
+if (oFalse == false); // renders true!
+if (oFalse == true);  // renders false
+
+if (oTrue == none);   // renders false
+if (oTrue == false);  // renders false
+if (oTrue == true);   // renders true
+
+

+ In other words, for optional<>, the following assertion does not hold: +

+
assert((opt == false) == (!opt));
+
-
-

-PrevUpHomeNext +PrevUpHomeNext
+

The implementation uses type_traits/alignment_of.hpp and type_traits/type_with_alignment.hpp

+
+ +

+ On compilers that do not conform to Standard C++ rules of reference binding, + operations on optional references might give adverse results: rather than + binding a reference to a designated object they may create an unexpected + temporary and bind to it. Compilers known to have these deficiencies include + GCC versions 4.2, 4.3, 4.4, 4.5; QCC 4.4.2; MSVC versions 8.0, 9.0, 10.0, + 11.0, 12.0. On these compilers prefer using direct-initialization and copy + assignment of optional references to copy-initialization and assignment from + T&: +

+
const int i = 0;
+optional<const int&> or1;
+optional<const int&> or2 = i;  // not portable
+or1 = i;                       // not portable
+
+optional<const int&> or3(i);   // portable
+or1 = optional<const int&>(i); // portable
+
+

+ In order to check if your compiler correctly implements reference binding + use this test program. +

+
#include <cassert>
+
+const int global_i = 0;
+
+struct TestingReferenceBinding
+{
+  TestingReferenceBinding(const int& ii)
+  {
+    assert(&ii == &global_i);
+  }
+
+  void operator=(const int& ii)
+  {
+    assert(&ii == &global_i);
+  }
+
+  void operator=(int&&) // remove this if your compiler doesn't have rvalue refs
+  {
+    assert(false);
+  }
+};
+
+int main()
+{
+  const int& iref = global_i;
+  assert(&iref == &global_i);
+
+  TestingReferenceBinding ttt = global_i;
+  ttt = global_i;
+
+  TestingReferenceBinding ttt2 = iref;
+  ttt2 = iref;
+}
+
+
-

-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_optional/detailed_semantics.html b/doc/html/boost_optional/detailed_semantics.html index 9f8b56b..4a5394e 100644 --- a/doc/html/boost_optional/detailed_semantics.html +++ b/doc/html/boost_optional/detailed_semantics.html @@ -2,8 +2,8 @@ Detailed Semantics - - + + @@ -72,7 +72,7 @@ space

- optional<T>::optional(); + optional<T>::optional() noexcept;

  • @@ -82,11 +82,7 @@ Postconditions: *this is uninitialized.
  • - Throws: Nothing. -
  • -
  • - Notes: T's default constructor is not - called. + Notes: T's default constructor is not called.
  • Example: @@ -99,7 +95,7 @@ space

    - optional<T>::optional( none_t ); + optional<T>::optional( none_t ) noexcept;

    • @@ -109,9 +105,6 @@
    • Postconditions: *this is uninitialized.
    • -
    • - Throws: Nothing. -
    • Notes: T's default constructor is not called. @@ -132,12 +125,16 @@ optional<T (not a ref)>::optional( T const& v )

      +
    • + Requires: is_copy_constructible<T>::value + is true. +
    • Effect: Directly-Constructs an optional.
    • Postconditions: *this is initialized - and its value is acopy of v. + and its value is a copy of v.
    • Throws: Whatever T::T( @@ -193,6 +190,58 @@
    +

    + space +

    +

    + optional<T (not a ref)>::optional( T&& + v ) +

    +
      +
    • + Requires: is_move_constructible<T>::value + is true. +
    • +
    • + Effect: Directly-Move-Constructs an optional. +
    • +
    • + Postconditions: *this is initialized + and its value is move-constructed from v. +
    • +
    • + Throws: Whatever T::T( + T&& + ) throws. +
    • +
    • + Notes: T::T( + T&& + ) is called. +
    • +
    • + Exception Safety: Exceptions can only + be thrown during T::T( T&& ); + in that case, the state of v + is determined by exception safety guarantees for T::T(T&&). +
    • +
    • + Example: +
      T v1, v2;
      +optional<T> opt(std::move(v1));
      +assert ( *opt == v2 ) ;
      +
      +
    • +
    +

    + space +

    +

    + optional<T&>::optional( T&& ref ) = delete +

    +
    • + Notes: This constructor is deleted +

    space

    @@ -229,6 +278,10 @@ optional<T (not a ref)>::optional( optional const& rhs );

    +
  • + Requires: is_copy_constructible<T>::value + is true. +
  • Effect: Copy-Constructs an optional.
  • @@ -320,6 +373,116 @@
+

+ space +

+

+ optional<T (not a ref)>::optional( optional&& rhs + ) noexcept(see below); +

+
    +
  • + Requires: is_move_constructible<T>::value + is true. +
  • +
  • + Effect: Move-constructs an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is move constructed from rhs; + else *this + is uninitialized. +
  • +
  • + Throws: Whatever T::T( + T&& + ) throws. +
  • +
  • + Notes: If rhs + is initialized, T::T( T + && ) + is called. The expression inside noexcept + is equivalent to is_nothrow_move_constructible<T>::value. +
  • +
  • + Exception Safety: Exceptions can only + be thrown during T::T( T&& ); + in that case, rhs remains + initialized and the value of *rhs is determined by exception safety + of T::T(T&&). +
  • +
  • + Example: +
    optional<std::unique_ptr<T>> uninit ;
    +assert (!uninit);
    +
    +optional<std::unique_ptr<T>> uinit2 ( std::move(uninit) ) ;
    +assert ( uninit2 == uninit );
    +
    +optional<std::unique_ptr<T>> init( std::uniqye_ptr<T>(new T(2)) );
    +assert ( **init == T(2) ) ;
    +
    +optional<std::unique_ptr<T>> init2 ( std::move(init) ) ;
    +assert ( init );
    +assert ( *init == nullptr );
    +assert ( init2 );
    +assert ( **init2 == T(2) ) ;
    +
    +
  • +
+

+ space +

+

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

+
    +
  • + Effect: Move-Constructs an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is another reference to the same object referenced + by *rhs; + else *this + is uninitialized. +
  • +
  • + Throws: Nothing. +
  • +
  • + Notes: If rhs + is initialized, both *this + and *rhs + will reefer to the same object (they alias). +
  • +
  • + Example: +
    optional<std::unique_ptr<T>&> uninit ;
    +assert (!uninit);
    +
    +optional<std::unique_ptr<T>&> uinit2 ( std::move(uninit) ) ;
    +assert ( uninit2 == uninit );
    +
    +std::unique_ptr<T> v(new T(2)) ;
    +optional<std::unique_ptr<T>&> init(v);
    +assert ( *init == v ) ;
    +
    +optional<std::unique_ptr<T>&> init2 ( std::move(init) ) ;
    +assert ( *init2 == v ) ;
    +
    +*v = 3 ;
    +
    +assert ( **init  == 3 ) ;
    +assert ( **init2 == 3 ) ;
    +
    +
  • +

space

@@ -368,6 +531,52 @@ +

+ space +

+

+ template<U> explicit optional<T + (not a ref)>::optional( optional<U>&& + rhs ); +

+
    +
  • + Effect: Move-constructs an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its 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 valid conversion from U + to T. +
  • +
  • + Exception Safety: Exceptions can only + be thrown during T::T( U&& ); + in that case, rhs remains + initialized and the value of *rhs is determined by exception safety + guarantee of T::T( U&& ). +
  • +
  • + Example: +
    optional<double> x(123.4);
    +assert ( *x == 123.4 ) ;
    +
    +optional<int> y(std::move(x)) ;
    +assert( *y == 123 ) ;
    +
    +
  • +

space

@@ -420,6 +629,22 @@ +

+ space +

+

+ optional& + optional<T>::operator= ( none_t ) noexcept; +

+
    +
  • + Effect: If *this is initialized destroys its contained + value. +
  • +
  • + Postconditions: *this is uninitialized. +
  • +

space

@@ -511,6 +736,66 @@ +

+ space +

+

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

+
    +
  • + Effect: Moves the value rhs to an optional. +
  • +
  • + Postconditions: *this is initialized and its value is moved + from rhs. +
  • +
  • + Throws: Whatever T::operator=( T&& ) + or T::T(T + &&) throws. +
  • +
  • + Notes: If *this was initialized, T's + move-assignment operator is used, otherwise, its move-constructor is used. +
  • +
  • + Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned + (it is up to T's operator=()). + If *this + is initially uninitialized and T's + move constructor fails, *this is left properly uninitialized. +
  • +
  • + Example: +
    T x;
    +optional<T> def ;
    +optional<T> opt(x) ;
    +
    +T y1, y2, yR;
    +def = std::move(y1) ;
    +assert ( *def == yR ) ;
    +opt = std::move(y2) ;
    +assert ( *opt == yR ) ;
    +
    +
  • +
+

+ space +

+

+ optional<T&>& + optional<T&>::operator= ( T&& + rhs ) + = delete; +

+
  • + Notes: This assignment operator is deleted. +

space

@@ -613,6 +898,75 @@ +

+ space +

+

+ optional& + optional<T (not a ref)>::operator= ( optional&& rhs + ) noexcept(see below); +

+
    +
  • + Effect: Move-assigns another optional to an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is moved from *rhs, rhs + remains initialized; else *this is uninitialized. +
  • +
  • + Throws: Whatever T::operator( T&& + ) or T::T( + T && + ) throws. +
  • +
  • + Notes: If both *this and rhs + are initially initialized, T's + move assignment operator is used. If *this is + initially initialized but rhs + is uninitialized, T's [destructor] + is called. If *this + is initially uninitialized but rhs + is initialized, T's move + constructor is called. The expression inside noexcept + is equivalent to is_nothrow_move_constructible<T>::value + && is_nothrow_move_assignable<T>::value. +
  • +
  • + Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned (it is up to T's + operator=()). + If *this + is initially uninitialized and T's + move constructor fails, *this is left properly uninitialized. +
  • +
  • + Example: +
    optional<T> opt(T(2)) ;
    +optional<T> def ;
    +
    +opt = def ;
    +assert ( def ) ;
    +assert ( opt ) ;
    +assert ( *opt == T(2) ) ;
    +
    +
  • +
+

+ space +

+

+ optional<T&> & optional<T&>::operator= ( optional<T&>&& + rhs ) + ; +

+
  • + Effect: Same as optional<T&>::operator= ( optional<T&> const& rhs ). +

space

@@ -673,6 +1027,59 @@ +

+ space +

+

+ template<U> optional& + optional<T (not a ref)>::operator= ( optional<U>&& + rhs ) + ; +

+
    +
  • + Effect: Move-assigns another convertible + optional to an optional. +
  • +
  • + Postconditions: If rhs + is initialized, *this + is initialized and its value is moved from the value of rhs; + else *this + is uninitialized. +
  • +
  • + Throws: Whatever T::operator=( U&& ) + or T::T( U&& ) + throws. +
  • +
  • + Notes: If both *this and rhs + are initially initialized, T's + assignment operator (from U&&) is used. If *this is initially initialized but rhs is uninitialized, T's + destructor is called. If *this is initially uninitialized but rhs is initialized, T's + converting constructor (from U&&) is called. +
  • +
  • + Exception Safety: In the event of an exception, + the initialization state of *this is unchanged and its value unspecified + as far as optional is concerned (it is up to T's + operator=()). + If *this + is initially uninitialized and T's + converting constructor fails, *this is left properly uninitialized. +
  • +
  • + Example: +
    T v;
    +optional<T> opt0(v);
    +optional<U> opt1;
    +
    +opt1 = std::move(opt0) ;
    +assert ( *opt1 == static_cast<U>(v) ) ;
    +
    +
  • +

space

@@ -731,7 +1138,7 @@ space

- void optional<T>::reset() ; + void optional<T>::reset() noexcept ;

  • Deprecated: Same as operator=( detail::none_t ); @@ -768,7 +1175,7 @@

  • - Requirements: *this is initialized + Requires: *this is initialized
  • Returns: A reference to the contained @@ -870,7 +1277,7 @@

  • - Requirements: *this is initialized + Requires: *this is initialized
  • Returns: The @@ -956,7 +1363,7 @@