Skip to content

Commit

Permalink
Add monadic operations (P2505) (#60, thanks @szaszm)
Browse files Browse the repository at this point in the history
* add and_then, or_else, transform and transform_error

- implement std::invoke as detail::invoke
- add the monadic functions from P2505
- write some tests

* clarify invoke member function implementation

I accidentally discovered that by declaring a templated data member
pointer type, the type can be deduced to a function type, resulting in a
member function pointer type. This was I could deduce cv-qualifiers and
noexcept-ness all in one, without having to resort to more
metaprogramming or writing 8x overloads.

Removed parens and added SFINAE checks to clarify that the parameter is
a member pointer type, and the member type gets deduced to a function
type, resulting in a member function pointer.

* nsel_P2505R configuration macro, R3 -> R5 impl

* update README
  • Loading branch information
szaszm committed Sep 30, 2023
1 parent 87ddd68 commit a314c9a
Show file tree
Hide file tree
Showing 3 changed files with 1,094 additions and 0 deletions.
38 changes: 38 additions & 0 deletions README.md
Expand Up @@ -127,6 +127,16 @@ Define this to 1 or 0 to control the use of SEH when C++ exceptions are disabled
\-D<b>nsel\_CONFIG\_CONFIRMS\_COMPILATION\_ERRORS</b>=0
Define this macro to 1 to experience the by-design compile-time errors of the library in the test suite. Default is 0.
#### Configure P2505 monadic operations
By default, *expected lite* provides monadic operations as described in [P2505R5](http://wg21.link/p2505r5). You can disable these operations by defining the following macro.
-D<b>nsel\_P2505R</b>=
You can use the R3 revision of P2505, which lacks `error_or`, and uses `remove_cvref` for transforms, by defining the following macro.
-D<b>nsel\_P2505R</b>=3
### Types in namespace nonstd
| Purpose | Type | Note / Object |
Expand Down Expand Up @@ -182,6 +192,24 @@ Define this macro to 1 to experience the by-design compile-time errors of the li
| &nbsp; | template&lt;typename Ex><br>bool **has_exception**() const | true of contains exception (as base) |
| &nbsp; | value_type **value_or**( U && v ) const & | value or move from v |
| &nbsp; | value_type **value_or**( U && v ) && | move from value or move from v |
| &nbsp; | constexpr error_type **error_or**( G && e ) const & | return current error or v [requires nsel_P2505R >= 4] |
| &nbsp; | constexpr error_type **error_or**( G && e ) && | move from current error or from v [requires nsel_P2505R >=4] |
| Monadic operations<br>(requires nsel_P2505R >= 3) | constexpr auto **and_then**( F && f ) & G| return f(value()) if has value, otherwise the error |
| &nbsp; | constexpr auto **and_then**( F && f ) const & | return f(value()) if has value, otherwise the error |
| &nbsp; | constexpr auto **and_then**( F && f ) && | return f(std::move(value())) if has value, otherwise the error |
| &nbsp; | constexpr auto **and_then**( F && f ) const && | return f(std::move(value())) if has value, otherwise the error |
| &nbsp; | constexpr auto **or_else**( F && f ) & | return the value, or f(error()) if there is no value |
| &nbsp; | constexpr auto **or_else**( F && f ) const & | return the value, or f(error()) if there is no value |
| &nbsp; | constexpr auto **or_else**( F && f ) && | return the value, or f(std::move(error())) if there is no value |
| &nbsp; | constexpr auto **or_else**( F && f ) const && | return the value, or f(std::move(error())) if there is no value |
| &nbsp; | constexpr auto **transform**( F && f ) & | return f(value()) wrapped if has value, otherwise the error |
| &nbsp; | constexpr auto **transform**( F && f ) const & | return f(value()) wrapped if has value, otherwise the error |
| &nbsp; | constexpr auto **transform**( F && f ) && | return f(std::move(value())) wrapped if has value, otherwise the error |
| &nbsp; | constexpr auto **transform**( F && f ) const && | return f(std::move(value())) wrapped if has value, otherwise the error |
| &nbsp; | constexpr auto **transform_error**( F && f ) & | return the value if has value, or f(error()) otherwise |
| &nbsp; | constexpr auto **transform_error**( F && f ) const & | return the value if has value, or f(error()) otherwise |
| &nbsp; | constexpr auto **transform_error**( F && f ) && | return the value if has value, or f(std::move(error())) otherwise |
| &nbsp; | constexpr auto **transform_error**( F && f ) const && | return the value if has value, or f(std::move(error())) otherwise |
| &nbsp; | ... | &nbsp; |
<a id="note1"></a>Note 1: checked access: if no content, for std::exception_ptr rethrows error(), otherwise throws bad_expected_access(error()).
Expand Down Expand Up @@ -425,6 +453,11 @@ expected: Allows to query if it contains an exception of a specific base type
expected: Allows to observe its value if available, or obtain a specified value otherwise
expected: Allows to move its value if available, or obtain a specified value otherwise
expected: Throws bad_expected_access on value access when disengaged
expected: Allows to observe its unexpected value, or fallback to the specified value with error_or
expected: Allows to map value with and_then
expected: Handling unexpected with or_else
expected: transform values
expected: Mapping errors with transform_error
expected<void>: Allows to default-construct
expected<void>: Allows to copy-construct from expected<void>: value
expected<void>: Allows to copy-construct from expected<void>: error
Expand All @@ -451,6 +484,11 @@ expected<void>: Allows to move its error
expected<void>: Allows to observe its error as unexpected
expected<void>: Allows to query if it contains an exception of a specific base type
expected<void>: Throws bad_expected_access on value access when disengaged
expected<void>: Observe unexpected value, or fallback to a default value with error_or
expected<void>: calling argless functions with and_then
expected<void>: or_else unexpected handling works
expected<void>: using transform to assign a new expected value
expected<void>: transform_error maps unexpected values
operators: Provides expected relational operators
operators: Provides expected relational operators (void)
swap: Allows expected to be swapped
Expand Down

0 comments on commit a314c9a

Please sign in to comment.