From 92f6fee49a79c0510b97c0676b5656b10abd4e40 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 27 Nov 2017 12:24:28 +0000 Subject: [PATCH 01/10] Update mutexes --- expected.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/expected.hpp b/expected.hpp index c1cd6cd..c764efe 100644 --- a/expected.hpp +++ b/expected.hpp @@ -69,7 +69,8 @@ namespace tl { template class expected; -#ifndef TL_OPTIONAL_EXPECTED_MUTEX +#ifndef TL_MONOSTATE_INPLACE_MUTEX +#define TL_MONOSTATE_INPLACE_MUTEX /// \brief Used to represent an expected with no data class monostate {}; @@ -156,7 +157,8 @@ static constexpr unexpect_t unexpect{}; /// \exclude namespace detail { -#ifndef TL_OPTIONAL_EXPECTED_MUTEX +#ifndef TL_TRAITS_MUTEX +#define TL_TRAITS_MUTEX // C++14-style aliases for brevity template using remove_const_t = typename std::remove_const::type; template From f2152f8e54a4ac4c1df832634209d247fb6f96ce Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 27 Nov 2017 14:24:22 +0000 Subject: [PATCH 02/10] Emplace tests --- expected.hpp | 13 +++++++++++-- tests/emplace.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/expected.hpp b/expected.hpp index c764efe..a923e0a 100644 --- a/expected.hpp +++ b/expected.hpp @@ -242,6 +242,9 @@ using expected_enable_from_other = detail::enable_if_t< /// \exclude namespace detail { +struct no_init_t{}; +static constexpr no_init_t no_init{}; + // Implements the storage of the values, and ensures that the destructor is // trivial if it can be. // @@ -252,6 +255,7 @@ template ::value, bool = std::is_trivially_destructible::value> struct expected_storage_base { constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_has_val(false) {} template ::value> * = @@ -297,6 +301,7 @@ struct expected_storage_base { // so the destructor of the `expected` can be trivial. template struct expected_storage_base { constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_has_val(false) {} template ::value> * = @@ -335,6 +340,7 @@ template struct expected_storage_base { // T is trivial, E is not. template struct expected_storage_base { constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_has_val(false) {} template ::value> * = @@ -378,6 +384,7 @@ template struct expected_storage_base { // E is trivial, T is not. template struct expected_storage_base { constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} + constexpr expected_storage_base(no_init_t) : m_has_val(false) {} template ::value> * = @@ -581,7 +588,8 @@ struct expected_copy_base : expected_operations_base { using expected_operations_base::expected_operations_base; expected_copy_base() = default; - expected_copy_base(const expected_copy_base &rhs) { + expected_copy_base(const expected_copy_base &rhs) : + expected_operations_base(no_init) { if (rhs.has_value()) { this->construct(rhs.get()); } else { @@ -616,7 +624,8 @@ struct expected_move_base : expected_copy_base { expected_move_base(const expected_move_base &rhs) = default; expected_move_base(expected_move_base &&rhs) noexcept( - std::is_nothrow_move_constructible::value) { + std::is_nothrow_move_constructible::value) : + expected_copy_base(no_init) { if (rhs.has_value()) { this->construct(std::move(rhs.get())); } else { diff --git a/tests/emplace.cpp b/tests/emplace.cpp index 6169541..c3b6023 100644 --- a/tests/emplace.cpp +++ b/tests/emplace.cpp @@ -1,4 +1,50 @@ #include "catch.hpp" #include "expected.hpp" +#include +#include +#include + +namespace { +struct takes_init_and_variadic { + std::vector v; + std::tuple t; + template + takes_init_and_variadic(std::initializer_list l, Args &&... args) + : v(l), t(std::forward(args)...) {} +}; +} TEST_CASE("Emplace", "[emplace]") { + { + tl::expected,int> e; + e.emplace(new int{42}); + REQUIRE(e); + REQUIRE(**e == 42); + } + + { + tl::expected,int> e; + e.emplace({0,1}); + REQUIRE(e); + REQUIRE((*e)[0] == 0); + REQUIRE((*e)[1] == 1); + } + + { + tl::expected,int> e; + e.emplace(2,3); + REQUIRE(e); + REQUIRE(std::get<0>(*e) == 2); + REQUIRE(std::get<1>(*e) == 3); + } + + { + tl::expected e = tl::make_unexpected(0); + e.emplace({0,1}, 2, 3); + REQUIRE(e); + REQUIRE(e->v[0] == 0); + REQUIRE(e->v[1] == 1); + REQUIRE(std::get<0>(e->t) == 2); + REQUIRE(std::get<1>(e->t) == 3); + } +} From afdacc1ba36bb14ff9ec74bdd94cb42e05e4db25 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 27 Nov 2017 14:48:16 +0000 Subject: [PATCH 03/10] More testing --- expected.hpp | 8 +-- tests/bases.cpp | 120 +++++++++++++++++++++++++++++++++++++++++ tests/constexpr.cpp | 6 +++ tests/constructors.cpp | 12 +++++ tests/noexcept.cpp | 6 +++ tests/observers.cpp | 36 +++++++++++++ tests/relops.cpp | 6 +++ 7 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 tests/bases.cpp create mode 100644 tests/constexpr.cpp create mode 100644 tests/noexcept.cpp create mode 100644 tests/observers.cpp create mode 100644 tests/relops.cpp diff --git a/expected.hpp b/expected.hpp index a923e0a..ebafc33 100644 --- a/expected.hpp +++ b/expected.hpp @@ -1537,22 +1537,22 @@ public: constexpr bool has_value() const noexcept { return this->m_has_val; } constexpr const T &value() const & { if (!has_value()) - throw bad_expected_access(err()); + throw bad_expected_access(err().value()); return val(); } TL_EXPECTED_11_CONSTEXPR T &value() & { if (!has_value()) - throw bad_expected_access(err()); + throw bad_expected_access(err().value()); return val(); } constexpr const T &&value() const && { if (!has_value()) - throw bad_expected_access(err()); + throw bad_expected_access(err().value()); return std::move(val()); } TL_EXPECTED_11_CONSTEXPR T &&value() && { if (!has_value()) - throw bad_expected_access(err()); + throw bad_expected_access(err().value()); return std::move(val()); } constexpr const E &error() const & { return err().value(); } diff --git a/tests/bases.cpp b/tests/bases.cpp new file mode 100644 index 0000000..9090f74 --- /dev/null +++ b/tests/bases.cpp @@ -0,0 +1,120 @@ +#include "catch.hpp" +#include "expected.hpp" + +TEST_CASE("Triviality", "[bases.triviality]") { + REQUIRE(std::is_trivially_copy_constructible>::value); + REQUIRE(std::is_trivially_copy_assignable>::value); + REQUIRE(std::is_trivially_move_constructible>::value); + REQUIRE(std::is_trivially_move_assignable>::value); + REQUIRE(std::is_trivially_destructible>::value); + + { + struct T { + T(const T&) = default; + T(T&&) = default; + T& operator=(const T&) = default; + T& operator=(T&&) = default; + ~T() = default; + }; + REQUIRE(std::is_trivially_copy_constructible>::value); + REQUIRE(std::is_trivially_copy_assignable>::value); + REQUIRE(std::is_trivially_move_constructible>::value); + REQUIRE(std::is_trivially_move_assignable>::value); + REQUIRE(std::is_trivially_destructible>::value); + } + + { + struct T { + T(const T&){} + T(T&&) {}; + T& operator=(const T&) {} + T& operator=(T&&) {}; + ~T(){} + }; + REQUIRE(!std::is_trivially_copy_constructible>::value); + REQUIRE(!std::is_trivially_copy_assignable>::value); + REQUIRE(!std::is_trivially_move_constructible>::value); + REQUIRE(!std::is_trivially_move_assignable>::value); + REQUIRE(!std::is_trivially_destructible>::value); + } + +} + +TEST_CASE("Deletion", "[bases.deletion]") { + REQUIRE(std::is_copy_constructible>::value); + REQUIRE(std::is_copy_assignable>::value); + REQUIRE(std::is_move_constructible>::value); + REQUIRE(std::is_move_assignable>::value); + REQUIRE(std::is_destructible>::value); + + { + struct T { + T()=default; + }; + REQUIRE(std::is_default_constructible>::value); + } + + { + struct T { + T(int); + }; + REQUIRE(!std::is_default_constructible>::value); + } + + { + struct T { + T(const T&) = default; + T(T&&) = default; + T& operator=(const T&) = default; + T& operator=(T&&) = default; + ~T() = default; + }; + REQUIRE(std::is_copy_constructible>::value); + REQUIRE(std::is_copy_assignable>::value); + REQUIRE(std::is_move_constructible>::value); + REQUIRE(std::is_move_assignable>::value); + REQUIRE(std::is_destructible>::value); + } + + { + struct T { + T(const T&)=delete; + T(T&&)=delete; + T& operator=(const T&)=delete; + T& operator=(T&&)=delete; + }; + REQUIRE(!std::is_copy_constructible>::value); + REQUIRE(!std::is_copy_assignable>::value); + REQUIRE(!std::is_move_constructible>::value); + REQUIRE(!std::is_move_assignable>::value); + } + + { + struct T { + T(const T&)=delete; + T(T&&)=default; + T& operator=(const T&)=delete; + T& operator=(T&&)=default; + }; + REQUIRE(!std::is_copy_constructible>::value); + REQUIRE(!std::is_copy_assignable>::value); + REQUIRE(std::is_move_constructible>::value); + REQUIRE(std::is_move_assignable>::value); + } + + { + struct T { + T(const T&)=default; + T(T&&)=delete; + T& operator=(const T&)=default; + T& operator=(T&&)=delete; + }; + REQUIRE(std::is_copy_constructible>::value); + REQUIRE(std::is_copy_assignable>::value); + //TODO see why this fails + //REQUIRE(!std::is_move_constructible>::value); + //REQUIRE(!std::is_move_assignable>::value); + } + + +} diff --git a/tests/constexpr.cpp b/tests/constexpr.cpp new file mode 100644 index 0000000..0fc0433 --- /dev/null +++ b/tests/constexpr.cpp @@ -0,0 +1,6 @@ +#include "catch.hpp" +#include "expected.hpp" + +TEST_CASE("Constexpr", "[constexpr]") { + //TODO +} diff --git a/tests/constructors.cpp b/tests/constructors.cpp index 219b168..817797b 100644 --- a/tests/constructors.cpp +++ b/tests/constructors.cpp @@ -18,6 +18,18 @@ TEST_CASE("Constructors", "[constructors]") { REQUIRE(e == 0); } + { + tl::expected e = tl::make_unexpected(0); + REQUIRE(!e); + REQUIRE(e.error() == 0); + } + + { + tl::expected e (tl::unexpect, 0); + REQUIRE(!e); + REQUIRE(e.error() == 0); + } + { tl::expected e (tl::in_place, 42); REQUIRE(e); diff --git a/tests/noexcept.cpp b/tests/noexcept.cpp new file mode 100644 index 0000000..5d1c1a0 --- /dev/null +++ b/tests/noexcept.cpp @@ -0,0 +1,6 @@ +#include "catch.hpp" +#include "expected.hpp" + +TEST_CASE("Noexcept", "[noexcept]") { + //TODO +} diff --git a/tests/observers.cpp b/tests/observers.cpp new file mode 100644 index 0000000..080e6be --- /dev/null +++ b/tests/observers.cpp @@ -0,0 +1,36 @@ +#include "catch.hpp" +#include "expected.hpp" + +struct move_detector { + move_detector() = default; + move_detector(move_detector &&rhs) { rhs.been_moved = true; } + bool been_moved = false; +}; + +TEST_CASE("Observers", "[observers]") { + tl::expected o1 = 42; + tl::expected o2 {tl::unexpect, 0}; + const tl::expected o3 = 42; + + REQUIRE(*o1 == 42); + REQUIRE(*o1 == o1.value()); + REQUIRE(o2.value_or(42) == 42); + REQUIRE(o2.error() == 0); + REQUIRE(o3.value() == 42); + auto success = std::is_same::value; + REQUIRE(success); + success = std::is_same::value; + REQUIRE(success); + success = std::is_same::value; + REQUIRE(success); + + #ifndef TL_EXPECTED_NO_CONSTRR + success = std::is_same::value; + REQUIRE(success); + #endif + + tl::expected o4{tl::in_place}; + move_detector o5 = std::move(o4).value(); + REQUIRE(o4->been_moved); + REQUIRE(!o5.been_moved); +} diff --git a/tests/relops.cpp b/tests/relops.cpp new file mode 100644 index 0000000..2314cee --- /dev/null +++ b/tests/relops.cpp @@ -0,0 +1,6 @@ +#include "catch.hpp" +#include "expected.hpp" + +TEST_CASE("Relational operators", "[relops]") { + //TODO +} From c3277f5a3566ec100a7532bed8ac62d11c5de592 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 27 Nov 2017 15:03:45 +0000 Subject: [PATCH 04/10] Update readme --- README.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 261fff0..072ddd0 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,61 @@ # expected -Single header, work-in-progress implementation of `std::expected` with functional-style extensions. +Single header implementation of `std::expected` with functional-style extensions. Clang + GCC: [![Linux Build Status](https://travis-ci.org/TartanLlama/expected.png?branch=master)](https://travis-ci.org/TartanLlama/expected) MSVC: [![Windows Build Status](https://ci.appveyor.com/api/projects/status/k5x00xa11y3s5wsg?svg=true)](https://ci.appveyor.com/project/TartanLlama/expected) +[`std::expected`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf) is proposed as the preferred way to represent object which will either have an expected value, or an unexpected value giving information about why something failed. Unfortunately, chaining together many computations which may fail can be verbose, as error-checking code will be mixed in with the actual programming logic. This implementation provides a number of utilities to make coding with `expected` cleaner. + +For example, instead of writing this code: + +``` +std::expected get_cute_cat (const image& img) { + auto cropped = crop_to_cat(img); + if (!cropped) { + return cropped; + } + + auto with_tie = add_bow_tie(*cropped); + if (!with_tie) { + return with_tie; + } + + auto with_sparkles = make_eyes_sparkle(*with_tie); + if (!with_sparkles) { + return with_sparkles; + } + + return add_rainbow(make_smaller(*with_sparkles)); +} +``` + +You can do this: + +``` +tl::expected get_cute_cat (const image& img) { + return crop_to_cat(img) + .and_then(add_bow_tie) + .and_then(make_eyes_sparkle) + .map(make_smaller) + .map(add_rainbow); +} +``` + Full documentation available at [expected.tartanllama.xyz](https://expected.tartanllama.xyz) +The interface is the same as `std::expected` as proposed in [p0323r3](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf), but the following member functions are also defined. Explicit types are for clarity. + +- `map`: carries out some operation on the stored object if there is one. + * `tl::expected s = exp_string.map(&std::string::size);` +- `map_error`: carries out some operation on the unexpected object if there is one. + * `my_error_code translate_error (std::error_code);` + * `tl::expected s = exp_int.map(translate_error);` +- `and_then`: like `map`, but for operations which return a `tl::expected`. + * `tl::expected parse (const std::string& s);` + * `tl::expected exp_ast = exp_string.and_then(parse);` +- `or_else`: calls some function if there is no value stored. + * `exp.or_else([] { throw std::runtime_error{"oh no"}; });` + ### Compiler support Tested on: From 66856b517ebc16cbc74f956e6d93ade9f7064cb8 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 27 Nov 2017 15:08:14 +0000 Subject: [PATCH 05/10] Update readme --- tests/bases.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/bases.cpp b/tests/bases.cpp index 9090f74..87b69b3 100644 --- a/tests/bases.cpp +++ b/tests/bases.cpp @@ -1,6 +1,11 @@ #include "catch.hpp" #include "expected.hpp" +// Old versions of GCC don't have the correct trait names. Could fix them up if needs be. +#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ + !defined(__clang__)) +// nothing for now +#else TEST_CASE("Triviality", "[bases.triviality]") { REQUIRE(std::is_trivially_copy_constructible>::value); REQUIRE(std::is_trivially_copy_assignable>::value); @@ -115,6 +120,6 @@ TEST_CASE("Deletion", "[bases.deletion]") { //REQUIRE(!std::is_move_constructible>::value); //REQUIRE(!std::is_move_assignable>::value); } - - } + +#endif From d37876102c97a7ec7910edf48f7df45f87e6ccb1 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 27 Nov 2017 15:11:47 +0000 Subject: [PATCH 06/10] Update docs --- docs/index.md | 278 ++++++++++++++++++++++++++------------------- standardese.config | 1 + 2 files changed, 161 insertions(+), 118 deletions(-) diff --git a/docs/index.md b/docs/index.md index 4075734..aeaf9a2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,144 +1,152 @@ # Header file `expected.hpp` -
#define TL_EXPECTED_HPP
+
#define TL_EXPECTED_HPP
 
-#define TL_EXPECTED_GCC49
+#define TL_EXPECTED_GCC49
 
-#define TL_EXPECTED_NO_CONSTRR
+#define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
 
-#define TL_EXPECTED_CXX14
+#define IS_TRIVIALLY_COPY_ASSIGNABLE(T)
 
-#define TL_IN_PLACE_MONOSTATE_DEFINED
+#define IS_TRIVIALLY_DESTRUCTIBLE(T)
 
-namespace tl
+#define TL_EXPECTED_CXX14
+
+#define TL_MONOSTATE_INPLACE_MUTEX
+
+#define TL_TRAITS_MUTEX
+
+#define TL_OPTIONAL_EXPECTED_MUTEX
+
+namespace tl
 {
-    class monostate;
+    class monostate;
     
-    struct in_place_t;
+    struct in_place_t;
     
-    constexpr in_place_t{} in_place;
+    constexpr in_place_t{} in_place;
     
     template <class E>
-    class unexpected;
+    class unexpected;
     
     template <class E>
-    constexpr bool operator==(const unexpected<E>& lhs, const unexpected<E>& rhs);
+    constexpr bool operator==(const unexpected<E>& lhs, const unexpected<E>& rhs);
     template <class E>
-    constexpr bool operator!=(const unexpected<E>& lhs, const unexpected<E>& rhs);
+    constexpr bool operator!=(const unexpected<E>& lhs, const unexpected<E>& rhs);
     template <class E>
-    constexpr bool operator<(const unexpected<E>& lhs, const unexpected<E>& rhs);
+    constexpr bool operator<(const unexpected<E>& lhs, const unexpected<E>& rhs);
     template <class E>
-    constexpr bool operator<=(const unexpected<E>& lhs, const unexpected<E>& rhs);
+    constexpr bool operator<=(const unexpected<E>& lhs, const unexpected<E>& rhs);
     template <class E>
-    constexpr bool operator>(const unexpected<E>& lhs, const unexpected<E>& rhs);
+    constexpr bool operator>(const unexpected<E>& lhs, const unexpected<E>& rhs);
     template <class E>
-    constexpr bool operator>=(const unexpected<E>& lhs, const unexpected<E>& rhs);
+    constexpr bool operator>=(const unexpected<E>& lhs, const unexpected<E>& rhs);
     
     template <class E>
-    unexpected<E> make_unexpected(E&& e);
+    unexpected<E> make_unexpected(E&& e);
     
-    struct unexpect_t;
+    struct unexpect_t;
     
-    constexpr unexpect_t{} unexpect;
+    constexpr unexpect_t{} unexpect;
     
     template <class E>
-    class bad_expected_access;
+    class bad_expected_access;
     
     template <class T, class E>
-    class expected;
+    class expected;
     
     template <class T, class E, class U, class F>
-    constexpr bool operator==(const expected<T, E>& lhs, const expected<U, F>& rhs);
+    constexpr bool operator==(const expected<T, E>& lhs, const expected<U, F>& rhs);
     
     template <class T, class E, class U, class F>
-    constexpr bool operator!=(const expected<T, E>& lhs, const expected<U, F>& rhs);
+    constexpr bool operator!=(const expected<T, E>& lhs, const expected<U, F>& rhs);
     
     template <class T, class E, class U, class F>
-    constexpr bool operator<(const expected<T, E>& lhs, const expected<U, F>& rhs);
+    constexpr bool operator<(const expected<T, E>& lhs, const expected<U, F>& rhs);
     
     template <class T, class E, class U, class F>
-    constexpr bool operator>(const expected<T, E>& lhs, const expected<U, F>& rhs);
+    constexpr bool operator>(const expected<T, E>& lhs, const expected<U, F>& rhs);
     
     template <class T, class E, class U, class F>
-    constexpr bool operator<=(const expected<T, E>& lhs, const expected<U, F>& rhs);
+    constexpr bool operator<=(const expected<T, E>& lhs, const expected<U, F>& rhs);
     
     template <class T, class E, class U, class F>
-    constexpr bool operator>=(const expected<T, E>& lhs, const expected<U, F>& rhs);
+    constexpr bool operator>=(const expected<T, E>& lhs, const expected<U, F>& rhs);
     
     template <class T, class E, class U>
-    constexpr bool operator==(const expected<T, E>& x, const U& v);
+    constexpr bool operator==(const expected<T, E>& x, const U& v);
     
     template <class T, class E, class U>
-    constexpr bool operator==(const U& v, const expected<T, E>& x);
+    constexpr bool operator==(const U& v, const expected<T, E>& x);
     
     template <class T, class E, class U>
-    constexpr bool operator!=(const expected<T, E>& x, const U& v);
+    constexpr bool operator!=(const expected<T, E>& x, const U& v);
     
     template <class T, class E, class U>
-    constexpr bool operator!=(const U& v, const expected<T, E>& x);
+    constexpr bool operator!=(const U& v, const expected<T, E>& x);
     
     template <class T, class E, class U>
-    constexpr bool operator<(const expected<T, E>& x, const U& v);
+    constexpr bool operator<(const expected<T, E>& x, const U& v);
     
     template <class T, class E, class U>
-    constexpr bool operator<(const U& v, const expected<T, E>& x);
+    constexpr bool operator<(const U& v, const expected<T, E>& x);
     
     template <class T, class E, class U>
-    constexpr bool operator<=(const expected<T, E>& x, const U& v);
+    constexpr bool operator<=(const expected<T, E>& x, const U& v);
     
     template <class T, class E, class U>
-    constexpr bool operator<=(const U& v, const expected<T, E>& x);
+    constexpr bool operator<=(const U& v, const expected<T, E>& x);
     
     template <class T, class E, class U>
-    constexpr bool operator>(const expected<T, E>& x, const U& v);
+    constexpr bool operator>(const expected<T, E>& x, const U& v);
     
     template <class T, class E, class U>
-    constexpr bool operator>(const U& v, const expected<T, E>& x);
+    constexpr bool operator>(const U& v, const expected<T, E>& x);
     
     template <class T, class E, class U>
-    constexpr bool operator>=(const expected<T, E>& x, const U& v);
+    constexpr bool operator>=(const expected<T, E>& x, const U& v);
     
     template <class T, class E, class U>
-    constexpr bool operator>=(const U& v, const expected<T, E>& x);
+    constexpr bool operator>=(const U& v, const expected<T, E>& x);
     
     template <class T, class E>
-    constexpr bool operator==(const expected<T, E>& x, const unexpected<E>& e);
+    constexpr bool operator==(const expected<T, E>& x, const unexpected<E>& e);
     
     template <class T, class E>
-    constexpr bool operator==(const unexpected<E>& e, const expected<T, E>& x);
+    constexpr bool operator==(const unexpected<E>& e, const expected<T, E>& x);
     
     template <class T, class E>
-    constexpr bool operator!=(const expected<T, E>& x, const unexpected<E>& e);
+    constexpr bool operator!=(const expected<T, E>& x, const unexpected<E>& e);
     
     template <class T, class E>
-    constexpr bool operator!=(const unexpected<E>& e, const expected<T, E>& x);
+    constexpr bool operator!=(const unexpected<E>& e, const expected<T, E>& x);
     
     template <class T, class E>
-    constexpr bool operator<(const expected<T, E>& x, const unexpected<E>& e);
+    constexpr bool operator<(const expected<T, E>& x, const unexpected<E>& e);
     
     template <class T, class E>
-    constexpr bool operator<(const unexpected<E>& e, const expected<T, E>& x);
+    constexpr bool operator<(const unexpected<E>& e, const expected<T, E>& x);
     
     template <class T, class E>
-    constexpr bool operator<=(const expected<T, E>& x, const unexpected<E>& e);
+    constexpr bool operator<=(const expected<T, E>& x, const unexpected<E>& e);
     
     template <class T, class E>
-    constexpr bool operator<=(const unexpected<E>& e, const expected<T, E>& x);
+    constexpr bool operator<=(const unexpected<E>& e, const expected<T, E>& x);
     
     template <class T, class E>
-    constexpr bool operator>(const expected<T, E>& x, const unexpected<E>& e);
+    constexpr bool operator>(const expected<T, E>& x, const unexpected<E>& e);
     
     template <class T, class E>
-    constexpr bool operator>(const unexpected<E>& e, const expected<T, E>& x);
+    constexpr bool operator>(const unexpected<E>& e, const expected<T, E>& x);
     
     template <class T, class E>
-    constexpr bool operator>=(const expected<T, E>& x, const unexpected<E>& e);
+    constexpr bool operator>=(const expected<T, E>& x, const unexpected<E>& e);
     
     template <class T, class E>
-    constexpr bool operator>=(const unexpected<E>& e, const expected<T, E>& x);
+    constexpr bool operator>=(const unexpected<E>& e, const expected<T, E>& x);
     
     template <class T, class E, 'hidden'>
-    void swap(expected<T, E>& lhs, expected<T, E>& rhs) noexcept(noexcept(lhs.swap(rhs)));
+    void swap(expected<T, E>& lhs, expected<T, E>& rhs) noexcept(noexcept(lhs.swap(rhs)));
 }
## Class `tl::monostate` @@ -153,14 +161,14 @@ Used to represent an expected with no data
struct in_place_t
 {
-    in_place_t() = default;
+    in_place_t() = default;
 };
A tag type to tell expected to construct its value in-place ## Variable `tl::in_place` -
constexpr in_place_t{} in_place;
+
constexpr in_place_t{} in_place;
A tag to tell expected to construct its value in-place @@ -170,15 +178,15 @@ A tag to tell expected to construct its value in-place class unexpected { public: - unexpected() = delete; + unexpected() = delete; - constexpr unexpected(const E& e); + constexpr unexpected(const E& e); - constexpr unexpected(E&& e); + constexpr unexpected(E&& e); - constexpr const E& value() const &; - constexpr E& value() &; - constexpr E&& value() &&; + constexpr const E& value() const &; + E& value() &; + E&& value() &&; };
Used as a wrapper to store the unexpected value @@ -187,9 +195,9 @@ Used as a wrapper to store the unexpected value
(1)  constexpr const E& value() const &;
 
-(2)  constexpr E& value() &;
+(2)  E& value() &;
 
-(3)  constexpr E&& value() &&;
+(3) E&& value() &&; *Returns*: the contained value @@ -198,22 +206,22 @@ Used as a wrapper to store the unexpected value ## Comparison operator `tl::operator==`
(1)  template <class E>
-     constexpr bool operator==(const unexpected<E>& lhs, const unexpected<E>& rhs);
+     constexpr bool operator==(const unexpected<E>& lhs, const unexpected<E>& rhs);
 
 (2)  template <class E>
-     constexpr bool operator!=(const unexpected<E>& lhs, const unexpected<E>& rhs);
+     constexpr bool operator!=(const unexpected<E>& lhs, const unexpected<E>& rhs);
 
 (3)  template <class E>
-     constexpr bool operator<(const unexpected<E>& lhs, const unexpected<E>& rhs);
+     constexpr bool operator<(const unexpected<E>& lhs, const unexpected<E>& rhs);
 
 (4)  template <class E>
-     constexpr bool operator<=(const unexpected<E>& lhs, const unexpected<E>& rhs);
+     constexpr bool operator<=(const unexpected<E>& lhs, const unexpected<E>& rhs);
 
 (5)  template <class E>
-     constexpr bool operator>(const unexpected<E>& lhs, const unexpected<E>& rhs);
+     constexpr bool operator>(const unexpected<E>& lhs, const unexpected<E>& rhs);
 
 (6)  template <class E>
-     constexpr bool operator>=(const unexpected<E>& lhs, const unexpected<E>& rhs);
+ constexpr bool operator>=(const unexpected<E>& lhs, const unexpected<E>& rhs); Compares two unexpected objects @@ -222,7 +230,7 @@ Simply compares lhs.value() to rhs.value() ## Function template `tl::make_unexpected`
template <class E>
-unexpected<E> make_unexpected(E&& e);
+unexpected<E> make_unexpected(E&& e); Create an `unexpected` from `e`, deducing the return type @@ -232,14 +240,14 @@ Create an `unexpected` from `e`, deducing the return type
struct unexpect_t
 {
-    unexpect_t() = default;
+    unexpect_t() = default;
 };
A tag type to tell expected to construct the unexpected value ## Variable `tl::unexpect` -
constexpr unexpect_t{} unexpect;
+
constexpr unexpect_t{} unexpect;
A tag to tell expected to construct the unexpected value @@ -249,112 +257,128 @@ A tag to tell expected to construct the unexpected value class expected { public: - using value_type = T; + using value_type = T; - using error_type = E; + using error_type = E; - using unexpected_type = unexpected<E>; + using unexpected_type = unexpected<E>; template <class F> - 'hidden' and_then(F&& f) &; + 'hidden' and_then(F&& f) &; template <class F> constexpr auto and_then(F &&f) &&; template <class F> constexpr auto and_then(F &&f) const &; + template <class F> + constexpr auto and_then(F &&f) const &&; template <class F> constexpr auto map(F &&f) &; template <class F> constexpr auto map(F &&f) &&; template <class F> constexpr auto map(F &&f) const &; + template <class F> constexpr auto map(F &&f) const &&; template <class F> constexpr auto map_error(F &&f) &; template <class F> constexpr auto map_error(F &&f) &&; template <class F> constexpr auto map_error(F &&f) const &; + template <class F> constexpr auto map_error(F &&f) const &&; - constexpr expected() = default; + template <class F> + expected or_else(F&& f) &; - constexpr expected(const expected& rhs) = default; + template <class F> + expected or_else(F&& f) &&; - constexpr expected(expected&& rhs) = default; + template <class F> + constexpr expected or_else(F&& f) const &; - constexpr expected& operator=(const expected& rhs) = default; + template <class F> + constexpr expected or_else(F&& f) const &&; - constexpr expected& operator=(expected&& rhs) = default; + constexpr expected() = default; + + constexpr expected(const expected& rhs) = default; + + constexpr expected(expected&& rhs) = default; + + expected& operator=(const expected& rhs) = default; + + expected& operator=(expected&& rhs) = default; template <class ... Args, 'hidden' ... = nullptr> - constexpr expected(in_place_t, Args&&... args); + constexpr expected(in_place_t, Args&&... args); template <class U, class ... Args, 'hidden' ... = nullptr> - constexpr expected(in_place_t, std::initializer_list<U> il, Args&&... args); + constexpr expected(in_place_t, std::initializer_list<U> il, Args&&... args); EXPLICIT constexpr expected(const unexpected<G> &e); EXPLICIT constexpr expected(unexpected<G> &&e); template <class ... Args, 'hidden' ... = nullptr> - constexpr expected(unexpect_t, Args&&... args); + constexpr expected(unexpect_t, Args&&... args); - template <class U, class G, 'hidden'> - constexpr expected(const expected<U, G>& rhs); + template <class U, class G, 'hidden', 'hidden'> + expected(const expected<U, G>& rhs); - template <class U, class G, 'hidden'> - constexpr expected(expected<U, G>&& rhs); - - template <class U = T, 'hidden'> - constexpr expected(U&& v); + template <class U, class G, 'hidden', 'hidden'> + expected(expected<U, G>&& rhs); template <class U = T, 'hidden', 'hidden'> - expected& operator=(U&& v); + constexpr expected(U&& v); + + template <class U = T, 'hidden', 'hidden'> + expected& operator=(U&& v); template <class G = E, 'hidden'> - expected& operator=(const unexpected<G>& rhs); + expected& operator=(const unexpected<G>& rhs); template <class G = E, 'hidden'> - expected& operator=(unexpected<G>&& rhs) noexcept; + expected& operator=(unexpected<G>&& rhs) noexcept; template <class ... Args, 'hidden' ... = nullptr> - void emplace(Args&&... args); + void emplace(Args&&... args); template <class U, class ... Args, 'hidden' ... = nullptr> - void emplace(std::initializer_list<U> il, Args&&... args); + void emplace(std::initializer_list<U> il, Args&&... args); - void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible<T>::value&&noexcept(swap(std::declval<T&>(), std::declval<T&>()))&&std::is_nothrow_move_constructible<E>::value&&noexcept(swap(std::declval<E&>(), std::declval<E&>()))); + void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible<T>::value&&noexcept(swap(std::declval<T&>(), std::declval<T&>()))&&std::is_nothrow_move_constructible<E>::value&&noexcept(swap(std::declval<E&>(), std::declval<E&>()))); - constexpr const T* operator->() const; + constexpr const T* operator->() const; - constexpr T* operator->(); + T* operator->(); - constexpr const T& operator*() const &; + constexpr const T& operator*() const &; - constexpr T& operator*() &; + T& operator*() &; - constexpr const T&& operator*() const &&; + constexpr const T&& operator*() const &&; - constexpr T&& operator*() &&; + T&& operator*() &&; - constexpr operator bool() const noexcept; + constexpr operator bool() const noexcept; - constexpr bool has_value() const noexcept; + constexpr bool has_value() const noexcept; - constexpr const T& value() const &; + constexpr const T& value() const &; - constexpr T& value() &; + T& value() &; - constexpr const T&& value() const &&; + constexpr const T&& value() const &&; - constexpr T&& value() &&; + T&& value() &&; - constexpr const E& error() const &; + constexpr const E& error() const &; - constexpr E& error() &; + E& error() &; - constexpr const E&& error() const &&; + constexpr const E&& error() const &&; - constexpr E&& error() &&; + E&& error() &&; template <class U> - constexpr T value_or(U&& v) const &; + constexpr T value_or(U&& v) const &; template <class U> - T value_or(U&& v) &&; + T value_or(U&& v) &&; }; An `expected` object is an object that contains the storage for another object and manages the lifetime of this contained object `T`. Alternatively it could contain the storage for another unexpected object `E`. The contained object may not be initialized after the expected object has been initialized, and may not be destroyed before the expected object has been destroyed. The initialization state of the contained object is tracked by the expected object. @@ -368,9 +392,12 @@ An `expected` object is an object that contains the storage for another ob constexpr auto and_then(F &&f) &&; (3) template <class F> - constexpr auto and_then(F &&f) const &; + constexpr auto and_then(F &&f) const &; -Carries out some operation which returns an optional on the stored object if there is one. \\requires `std::invoke(std::forward(f), value())` returns a `std::optional` for some `U`. \\returns Let `U` be the result of `std::invoke(std::forward(f), value())`. Returns a `std::optional`. The return value is empty if `*this` is empty, otherwise the return value of `std::invoke(std::forward(f), value())` is returned. \\group and\_then \\synopsis template \\\nconstexpr auto and\_then(F &\&f) &; +(4) template <class F> + constexpr auto and_then(F &&f) const &&; + +Carries out some operation which returns an expected on the stored object if there is one. \\requires `std::invoke(std::forward(f), value())` returns a `std::expected` for some `U`. \\returns Let `U` be the result of `std::invoke(std::forward(f), value())`. Returns a `std::expected`. The return value is empty if `*this` is empty, otherwise the return value of `std::invoke(std::forward(f), value())` is returned. \\group and\_then \\synopsis template \\\nconstexpr auto and\_then(F &\&f) &; ### Function template `tl::expected::map` @@ -378,7 +405,9 @@ Carries out some operation which returns an optional on the stored object if the (2) template <class F> constexpr auto map(F &&f) &&; -(3) template <class F> constexpr auto map(F &&f) const &; +(3) template <class F> constexpr auto map(F &&f) const &; + +(4) template <class F> constexpr auto map(F &&f) const &&; Carries out some operation on the stored object if there is one. @@ -390,12 +419,25 @@ Carries out some operation on the stored object if there is one. (2) template <class F> constexpr auto map_error(F &&f) &&; -(3) template <class F> constexpr auto map_error(F &&f) const &; +(3) template <class F> constexpr auto map_error(F &&f) const &; + +(4) template <class F> constexpr auto map_error(F &&f) const &&; Carries out some operation on the stored unexpected object if there is one. *Returns*: Let `U` be the result of `std::invoke(std::forward(f), value())`. Returns a `std::expected`. If `*this` has an expected value, the result is `*this`, otherwise an `expected` is constructed from `make_unexpected(std::invoke(std::forward(f), value()))` and is returned. +### Function template `tl::expected::or_else` + +
(1)  template <class F>
+     expected or_else(F&& f) &;
+ +Calls `f` if the expectd is in the unexpected state + +*Requires*: `std::invoke_result_t` must be void or convertible to `expcted`. + +*Effects*: If `*this` has a value, returns `*this`. Otherwise, if `f` returns `void`, calls `std::forward(f)` and returns `std::nullopt`. Otherwise, returns `std::forward(f)()`. + ### Function template `tl::expected::expected`
(1)  EXPLICIT constexpr expected(const unexpected<G> &e);
diff --git a/standardese.config b/standardese.config
index bdd6d9b..643fd3b 100644
--- a/standardese.config
+++ b/standardese.config
@@ -1,2 +1,3 @@
 [output]
 format=commonmark
+link_extension=html

From e61179684cc81655c0ee9653a64a535142611f54 Mon Sep 17 00:00:00 2001
From: Simon Brand 
Date: Mon, 27 Nov 2017 15:17:46 +0000
Subject: [PATCH 07/10] Update docs

---
 docs/index.md | 6 +++---
 expected.hpp  | 8 ++++----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/docs/index.md b/docs/index.md
index aeaf9a2..57b57e1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -264,7 +264,7 @@ public:
     using unexpected_type = unexpected<E>;
     
     template <class F>
-    'hidden' and_then(F&& f) &;
+    constexpr auto and_then(F &&f) &;
     template <class F>
     constexpr auto and_then(F &&f) &&;
     template <class F>
@@ -386,7 +386,7 @@ An `expected` object is an object that contains the storage for another ob
 ### Function template `tl::expected::and_then`
 
 
(1)  template <class F>
-     'hidden' and_then(F&& f) &;
+     constexpr auto and_then(F &&f) &;
 
 (2)  template <class F>
      constexpr auto and_then(F &&f) &&;
@@ -397,7 +397,7 @@ An `expected` object is an object that contains the storage for another ob
 (4)  template <class F>
      constexpr auto and_then(F &&f) const &&;
-Carries out some operation which returns an expected on the stored object if there is one. \\requires `std::invoke(std::forward(f), value())` returns a `std::expected` for some `U`. \\returns Let `U` be the result of `std::invoke(std::forward(f), value())`. Returns a `std::expected`. The return value is empty if `*this` is empty, otherwise the return value of `std::invoke(std::forward(f), value())` is returned. \\group and\_then \\synopsis template \\\nconstexpr auto and\_then(F &\&f) &; +Carries out some operation which returns an expected on the stored object if there is one. \\requires `std::invoke(std::forward(f), value())` returns a `std::expected` for some `U`. \\returns Let `U` be the result of `std::invoke(std::forward(f), value())`. Returns a `std::expected`. The return value is empty if `*this` is empty, otherwise the return value of `std::invoke(std::forward(f), value())` is returned. ### Function template `tl::expected::map` diff --git a/expected.hpp b/expected.hpp index ebafc33..61b567c 100644 --- a/expected.hpp +++ b/expected.hpp @@ -911,8 +911,8 @@ public: /// of `std::invoke(std::forward(f), value())`. Returns a /// `std::expected`. The return value is empty if `*this` is empty, /// otherwise the return value of `std::invoke(std::forward(f), value())` - /// is returned. \group and_then \synopsis template \nconstexpr auto - /// and_then(F &&f) &; + /// is returned. + /// \synopsis template \nconstexpr auto and_then(F &&f) &; template TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { using result = detail::invoke_result_t; static_assert(detail::is_expected::value, @@ -965,8 +965,8 @@ public: /// of `std::invoke(std::forward(f), value())`. Returns a /// `std::expected`. The return value is empty if `*this` is empty, /// otherwise the return value of `std::invoke(std::forward(f), value())` - /// is returned. \group and_then \synopsis template \nconstexpr auto - /// and_then(F &&f) &; + /// is returned. + /// \synopsis template \nconstexpr auto and_then(F &&f) &; template TL_EXPECTED_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { using result = detail::invoke_result_t; From 9abc013e435a172db869070804f6700bb6a12800 Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Mon, 27 Nov 2017 15:19:17 +0000 Subject: [PATCH 08/10] Update docs --- docs/index.md | 10 ++-------- expected.hpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/index.md b/docs/index.md index 57b57e1..a42fec2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,15 +2,9 @@
#define TL_EXPECTED_HPP
 
-#define TL_EXPECTED_GCC49
+#define TL_EXPECTED_VERSION_MAJOR
 
-#define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)
-
-#define IS_TRIVIALLY_COPY_ASSIGNABLE(T)
-
-#define IS_TRIVIALLY_DESTRUCTIBLE(T)
-
-#define TL_EXPECTED_CXX14
+#define TL_EXPECTED_VERSION_MINOR
 
 #define TL_MONOSTATE_INPLACE_MUTEX
 
diff --git a/expected.hpp b/expected.hpp
index 61b567c..075030d 100644
--- a/expected.hpp
+++ b/expected.hpp
@@ -14,6 +14,9 @@
 #ifndef TL_EXPECTED_HPP
 #define TL_EXPECTED_HPP
 
+#define TL_EXPECTED_VERSION_MAJOR 0
+#define TL_EXPECTED_VERSION_MINOR 1
+
 #include 
 #include 
 #include 
@@ -21,38 +24,49 @@
 #include 
 
 #if (defined(_MSC_VER) && _MSC_VER == 1900)
+/// \exclude
 #define TL_EXPECTED_MSVC2015
 #endif
 
 #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9)
+/// \exclude
 #define TL_EXPECTED_GCC49
 #endif
 
 #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4)
+/// \exclude
 #define TL_EXPECTED_GCC54
 #endif
 
 #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 &&              \
      !defined(__clang__))
 // GCC < 5 doesn't support overloading on const&& for member functions
+/// \exclude
 #define TL_EXPECTED_NO_CONSTRR
 
 // GCC < 5 doesn't support some standard C++11 type traits
+/// \exclude
 #define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)                                     \
   std::has_trivial_copy_constructor::value
+/// \exclude
 #define IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign::value
 
 // This one will be different for GCC 5.7 if it's ever supported
+/// \exclude
 #define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
 #else
+/// \exclude
 #define IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)                                     \
   std::is_trivially_copy_constructible::value
+/// \exclude
 #define IS_TRIVIALLY_COPY_ASSIGNABLE(T)                                        \
   std::is_trivially_copy_assignable::value
+/// \exclude
 #define IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
 #endif
 
 #if __cplusplus > 201103L
+/// \exclude
 #define TL_EXPECTED_CXX14
 #endif
 

From e081092fb1469633c59dd8447f8eaf9db0095e65 Mon Sep 17 00:00:00 2001
From: Simon Brand 
Date: Mon, 27 Nov 2017 15:23:46 +0000
Subject: [PATCH 09/10] Docs

---
 docs/index.md | 116 +++++++++++++++++++++++++++++++++++++-------------
 expected.hpp  |  35 ++++++++++++++-
 2 files changed, 120 insertions(+), 31 deletions(-)

diff --git a/docs/index.md b/docs/index.md
index a42fec2..a27e863 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -336,43 +336,31 @@ public:
     
     void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible<T>::value&&noexcept(swap(std::declval<T&>(), std::declval<T&>()))&&std::is_nothrow_move_constructible<E>::value&&noexcept(swap(std::declval<E&>(), std::declval<E&>())));
     
-    constexpr const T* operator->() const;
+    constexpr const T* operator->() const;
+    T* operator->();
     
-    T* operator->();
+    constexpr const T& operator*() const &;
+    T& operator*() &;
+    constexpr const T&& operator*() const &&;
+    T&& operator*() &&;
     
-    constexpr const T& operator*() const &;
+    constexpr bool has_value() const noexcept;
+    constexpr operator bool() const noexcept;
     
-    T& operator*() &;
+    constexpr const T& value() const &;
+    T& value() &;
+    constexpr const T&& value() const &&;
+    T&& value() &&;
     
-    constexpr const T&& operator*() const &&;
-    
-    T&& operator*() &&;
-    
-    constexpr operator bool() const noexcept;
-    
-    constexpr bool has_value() const noexcept;
-    
-    constexpr const T& value() const &;
-    
-    T& value() &;
-    
-    constexpr const T&& value() const &&;
-    
-    T&& value() &&;
-    
-    constexpr const E& error() const &;
-    
-    E& error() &;
-    
-    constexpr const E&& error() const &&;
-    
-    E&& error() &&;
+    constexpr const E& error() const &;
+    E& error() &;
+    constexpr const E&& error() const &&;
+    E&& error() &&;
     
     template <class U>
-    constexpr T value_or(U&& v) const &;
-    
+    constexpr T value_or(U&& v) const &;
     template <class U>
-    T value_or(U&& v) &&;
+    T value_or(U&& v) &&;
 };
An `expected` object is an object that contains the storage for another object and manages the lifetime of this contained object `T`. Alternatively it could contain the storage for another unexpected object `E`. The contained object may not be initialized after the expected object has been initialized, and may not be destroyed before the expected object has been destroyed. The initialization state of the contained object is tracked by the expected object. @@ -438,6 +426,74 @@ Calls `f` if the expectd is in the unexpected state (2) EXPLICIT constexpr expected(unexpected<G> &&e);
+### Operator `tl::expected::operator->` + +
(1)  constexpr const T* operator->() const;
+
+(2)  T* operator->();
+ +*Returns*: a pointer to the stored value + +*Requires*: a value is stored + +### Operator `tl::expected::operator*` + +
(1)  constexpr const T& operator*() const &;
+
+(2)  T& operator*() &;
+
+(3)  constexpr const T&& operator*() const &&;
+
+(4)  T&& operator*() &&;
+ +*Returns*: the stored value + +*Requires*: a value is stored + +### Function `tl::expected::has_value` + +
(1)  constexpr bool has_value() const noexcept;
+
+(2)  constexpr operator bool() const noexcept;
+ +*Returns*: whether or not the optional has a value + +### Function `tl::expected::value` + +
(1)  constexpr const T& value() const &;
+
+(2)  T& value() &;
+
+(3)  constexpr const T&& value() const &&;
+
+(4)  T&& value() &&;
+ +*Returns*: the contained value if there is one, otherwise throws \[bad\_expected\_access\] + +### Function `tl::expected::error` + +
(1)  constexpr const E& error() const &;
+
+(2)  E& error() &;
+
+(3)  constexpr const E&& error() const &&;
+
+(4)  E&& error() &&;
+ +*Returns*: the unexpected value + +*Requires*: there is an unexpected value + +### Function template `tl::expected::value_or` + +
(1)  template <class U>
+     constexpr T value_or(U&& v) const &;
+
+(2)  template <class U>
+     T value_or(U&& v) &&;
+ +*Returns*: the stored value if there is one, otherwise returns `u` + ----- ----- diff --git a/expected.hpp b/expected.hpp index 075030d..c9dda07 100644 --- a/expected.hpp +++ b/expected.hpp @@ -1541,44 +1541,77 @@ public: } } + /// \returns a pointer to the stored value + /// \requires a value is stored + /// \group pointer constexpr const T *operator->() const { return valptr(); } + /// \group pointer TL_EXPECTED_11_CONSTEXPR T *operator->() { return valptr(); } + + /// \returns the stored value + /// \requires a value is stored + /// \group deref constexpr const T &operator*() const & { return val(); } + /// \group deref TL_EXPECTED_11_CONSTEXPR T &operator*() & { return val(); } + /// \group deref constexpr const T &&operator*() const && { return std::move(val()); } + /// \group deref TL_EXPECTED_11_CONSTEXPR T &&operator*() && { return std::move(val()); } - constexpr explicit operator bool() const noexcept { return this->m_has_val; } + + /// \returns whether or not the optional has a value + /// \group has_value constexpr bool has_value() const noexcept { return this->m_has_val; } + /// \group has_value + constexpr explicit operator bool() const noexcept { return this->m_has_val; } + + + /// \returns the contained value if there is one, otherwise throws [bad_expected_access] + /// \group value constexpr const T &value() const & { if (!has_value()) throw bad_expected_access(err().value()); return val(); } + /// \group value TL_EXPECTED_11_CONSTEXPR T &value() & { if (!has_value()) throw bad_expected_access(err().value()); return val(); } + /// \group value constexpr const T &&value() const && { if (!has_value()) throw bad_expected_access(err().value()); return std::move(val()); } + /// \group value TL_EXPECTED_11_CONSTEXPR T &&value() && { if (!has_value()) throw bad_expected_access(err().value()); return std::move(val()); } + + /// \returns the unexpected value + /// \requires there is an unexpected value + /// \group error constexpr const E &error() const & { return err().value(); } + /// \group error TL_EXPECTED_11_CONSTEXPR E &error() & { return err().value(); } + /// \group error constexpr const E &&error() const && { return std::move(err().value()); } + /// \group error TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(err().value()); } + + /// \returns the stored value if there is one, otherwise returns `u` + /// \group value_or template constexpr T value_or(U &&v) const & { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy-constructible and convertible to from U&&"); return bool(*this) ? **this : static_cast(std::forward(v)); } + /// \group value_or template TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { static_assert(std::is_move_constructible::value && std::is_convertible::value, From b4f9e3d224a2ee2550fa1665935f922a8816a981 Mon Sep 17 00:00:00 2001 From: ericLemanissier Date: Wed, 29 Nov 2017 13:53:45 +0100 Subject: [PATCH 10/10] replace optional by expected in readme license --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 072ddd0..529a3e3 100644 --- a/README.md +++ b/README.md @@ -86,4 +86,4 @@ Requires [Catch](https://github.com/philsquared/Catch) for testing. This is bund [![CC0](http://i.creativecommons.org/p/zero/1.0/88x31.png)]("http://creativecommons.org/publicdomain/zero/1.0/") -To the extent possible under law, [Simon Brand](https://twitter.com/TartanLlama) has waived all copyright and related or neighboring rights to the `optional` library. This work is published from: United Kingdom. +To the extent possible under law, [Simon Brand](https://twitter.com/TartanLlama) has waived all copyright and related or neighboring rights to the `expected` library. This work is published from: United Kingdom.