From 4d9e404fb05eaaaff4fa493708b73fc2c7a21cf0 Mon Sep 17 00:00:00 2001 From: "Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com)" Date: Thu, 11 May 2017 01:09:02 +0100 Subject: [PATCH] Did another pass of the docs. Very close to peer review ready now. --- Readme.md | 4 +- doc/html | 2 +- doc/md/00-mainpage.md | 2 +- doc/md/01-installation.md | 2 +- doc/md/02-tutorialA.md | 18 ++++- doc/md/03-tutorialB.md | 4 +- doc/md/04-tutorialC.md | 107 +++++++++++++++++++++---- doc/md/08-expectedsynopsis.md | 19 +++-- example/expected_try1.cpp | 2 +- example/expected_try2.cpp | 2 +- example/expected_try3.cpp | 2 +- include/boost/outcome/outcome_v1.0.hpp | 40 ++++----- include/boost/outcome/revision.hpp | 6 +- 13 files changed, 150 insertions(+), 60 deletions(-) diff --git a/Readme.md b/Readme.md index 19c9ce2cd3..d93712b1a1 100644 --- a/Readme.md +++ b/Readme.md @@ -13,8 +13,8 @@ Past tarballs of source with all tests passing on Linux and Windows: https://ded Before Boost peer review: - [ ] Write up errata for ACCU talk for under the video. - - [x] Fix operator*(), operator->() and .error() in Expected. - - [x] error_or() ought to have rvalue ref etc overloads, and exception_or() + - [x] Fix operator*(), operator->() and .error() in Expected [issus #10]. + - [x] error_or() ought to have rvalue ref etc overloads, and exception_or() [issue #10]. Later after Boost peer review: - [ ] Create new Win32 and NT error code categories and have make_errored_outcome() use those. diff --git a/doc/html b/doc/html index 36e28933fb..2fb650e7fe 160000 --- a/doc/html +++ b/doc/html @@ -1 +1 @@ -Subproject commit 36e28933fbea597b3987a6caf956792f37cc0af2 +Subproject commit 2fb650e7fefded65517b3fb777ab1cc86aa5b69e diff --git a/doc/md/00-mainpage.md b/doc/md/00-mainpage.md index d373b85809..f86f6c2f23 100644 --- a/doc/md/00-mainpage.md +++ b/doc/md/00-mainpage.md @@ -61,7 +61,7 @@ affect some applications. In this situation, use LLVM clang targeting the MSVC A \page support Support -StackOverflow with the boost-outcome tag is the +StackOverflow with the boost-outcome tag is the preferred place to ask questions on usage. If you have a problem, please review the FAQ and the wiki. Searching diff --git a/doc/md/01-installation.md b/doc/md/01-installation.md index 37d34881a2..53d397866c 100644 --- a/doc/md/01-installation.md +++ b/doc/md/01-installation.md @@ -7,7 +7,7 @@ OS X with Xcode and on Windows with VS2015. A nightly cronjob figures out for which latest commit all tests passed on all those platforms and merges that commit to master branch. From that master branch, a source tarball is generated. -Under a default configuration, when you `#include "boost.outcome/include/boost/outcome.hpp"` +Under a default configuration, when you \#include "boost.outcome/include/boost/outcome.hpp" you will include a preprocessed single file edition for maximum build performance in downstream projects. This can interfere with accurate bug reporting in Outcome, so if you are diagnosing a problem in Outcome itself, predefine diff --git a/doc/md/02-tutorialA.md b/doc/md/02-tutorialA.md index 2cc7348c66..d49f6ad28e 100644 --- a/doc/md/02-tutorialA.md +++ b/doc/md/02-tutorialA.md @@ -545,6 +545,18 @@ valueless due to exception state ever appears, we throw a `bad_expected_access` is not a possible Expected configuration due to requiring E to be constructible. +\note By default Outcome static asserts if you use any its transports with a type or types +which have throwing move constructors, warning you that in that use case you must write code +to cope with valueless due to exception. These static asserts can be disabled using a type trait +on a type by type basis, but this default behaviour will prevent accidental surprises when using +Outcome's non-conforming Expected implementation. + +\warning These sorts of monadic transport are particularly sensitive to generating code and memory +bloat if their move constructor can throw due to all the extra work Outcome must do to ensure +exception safety. Try, whenever possible, to only use types in these transports with +non-throwing move semantics (i.e. don't quickly disable the static assert above unless there +is no other option available). + \subsubsection expected_observers Expected's observers Generally speaking you will not want Expected to throw `bad_expected_access` as a @@ -566,10 +578,10 @@ public: using type = expected; }; - // As if &value() + // As if reinterpret_cast, no runtime checking performed! constexpr const T* operator ->() const; T* operator ->(); - // As if value() + // As if reinterpret_cast, no runtime checking performed! constexpr const T& operator *() const&; T& operator *() &; constexpr const T&& operator *() const &&; @@ -585,7 +597,7 @@ public: constexpr const T&& value() const &&; constexpr T&& value() &&; - // Returns a lvalue or rvalue ref to the stored error_type if there is one, else undefined behaviour + // As if reinterpret_cast, no runtime checking performed! constexpr const E& error() const&; E& error() &; constexpr E&& error() &&; diff --git a/doc/md/03-tutorialB.md b/doc/md/03-tutorialB.md index 406b04ffd9..052a66e961 100644 --- a/doc/md/03-tutorialB.md +++ b/doc/md/03-tutorialB.md @@ -58,7 +58,7 @@ maintenance burden over time is obvious, and a further worked example follows be The third reason is that the C++ 11 standard library already provides an enum of the most common error codes for you so you don't feel like going off and reinventing the wheel. It's called `std::errc` -brought in by `#include ` and as you'll see, it contains the standard +brought in by \#include and as you'll see, it contains the standard POSIX error codes, and most of the time you'll find that whatever custom error code domain you are about to write can be adequately covered by `std::errc`. In fact, let's try it: @@ -202,7 +202,7 @@ abstraction layer where errors from the OS ought to be returned exactly as from you should leave `E` default to `std::error_code` and return `std::system_category()` error codes from `errno` or `GetLastError()` as appropriate. If you don't care and/or you're in a rush, `E = std::error_code` and returning some enumeration from `std::errc` will get you working code -the quickest (and be aware that Outcome's refinements of `expected` `outcome` and `result` +the quickest (and be aware that Outcome's refinements of `expected`, `outcome` and `result` hard code the `E` to an enhanced `error_code_extended` and will save you typing a fair bit of boilerplate). As the latter two use patterns may be unclear, a worked example follows in the next section. diff --git a/doc/md/04-tutorialC.md b/doc/md/04-tutorialC.md index f96677e4ee..59d043970d 100644 --- a/doc/md/04-tutorialC.md +++ b/doc/md/04-tutorialC.md @@ -208,6 +208,9 @@ instead there is a formal empty state to do with as you please (in some situatio returning a value OR empty OR an error makes a lot of sense and Outcome supports a `tribool` extension for ternary logics for those who need such a thing). Attempting to retrieve a value, error or exception from an empty transport throws a `monad_error::no_state` [1]. + - Implied in this design is that unlike in Expected, your type `T` need not be default + constructible, nor movable, nor copyable. If your type `T` throws during a switch between + states, we adopt the formal empty state. - `.value()` on an errored transport directly throws a `std::system_error` with the error code [2] instead of throwing a wrapper type like `bad_expected_access` from which you need to manually extract the `E` instance later. @@ -217,15 +220,29 @@ extract later. - `.error()` returns any `error_code_extended` as you'd expect, returning a default constructed (null) error code if the transport is valued, or `monad_errc::exception_present` if the transport is excepted. + - Unlike Expected, this is always a by-value return instead of by-reference via +`reinterpret_cast`. This is low cost, because we know what our error type always is. - `.exception()` returns any `std::exception_ptr` as you'd expect. If the transport is valued, it returns a default constructed (null) exception pointer. If the transport is errored, it returns an exception pointer to a `std::system_error` wrapping the error code. - -And finally, if your compiler is in C++ 17 mode or later, transports are marked with the +- `operator->()` and `operator*()` both alias `.value()` i.e. they do not implicitly do +`reinterpret_cast` like Expected does. In fact, Outcome's refinements **never ever** +implicitly call `reinterpret_cast<>`, and you can make use of this to save writing considerable +boilerplate by letting these throwing semantics just described activate as needed instead of +you having to manually check state before access as you must do with Expected. +- Due to historically also providing a monadic future-promise implementation, we also provide `.get()`, +`.get_error()`, `.get_exception()` and so on. These are aliases to `.value()`, `.error()` and +`.exception()`. We have found the aliases useful in our own code where we use the convention of +`.value()` when we make use of the value returned, and `.get()` to indicate we are purely +retrieving the value to cause the rethrow of any errors or exceptions. We have found this makes +code clearer. You may find using the same convention useful in your own code too. + +Additionally, if your compiler is in C++ 17 mode or later, transports are marked with the `[[nodiscard]]` attribute. This means the compiler ought to warn if you forget to examine transports returned by functions. If you really mean to throw away a returned transport, make sure you cast it to `(void)` to tell -the compiler you specifically intend to throw it away. +the compiler you specifically intend to throw it away. This solves a big pain point when using +`error_code &ec` pass back overloads from C++ 11 where you forget to check `ec`. [1]: Actually the `BOOST_OUTCOME_THROW_MONAD_ERROR(ec, monad_error(monad_errc::no_state))` macro is executed where `ec` is the `std::error_code` contained by the monad. This can be user redefined to do anything, @@ -265,12 +282,12 @@ result somefunction() The full set of free functions is as follows:
-
`make_[option|result|outcome](T v)`
-
Makes a valued transport with value `v`.
-
`make_[option|result|outcome]()`
-
Makes a valued transport default constructing a `T`.
`make_empty_[option|result|outcome]()`
Makes an empty transport.
+
`make_valued_[option|result|outcome](T v)`
+
Makes a valued transport with value `v`.
+
`make_valued_[option|result|outcome]()`
+
Makes a valued transport default constructing a `T`.
`make_errored_[result|outcome](error_code_extended ec)`
Makes an errored transport.
`make_errored_[result|outcome](int code, const char *extendedmsg = nullptr)`
@@ -281,7 +298,7 @@ very convenient for writing: result somefunction() { if(-1 == open(...)) // Any POSIX system call setting errno on failure - return make_errored_result<>(errno); + return make_errored_result(errno); } ~~~ @@ -294,7 +311,7 @@ very convenient for writing: result somefunction() { if(INVALID_HANDLE_VALUE == CreateFile(...)) // Any Win32 call setting GetLastError() on failure - return make_errored_result<>(GetLastError()); + return make_errored_result(GetLastError()); } ~~~ @@ -309,7 +326,7 @@ very convenient for writing: } catch(...) // catch all { - return make_exceptional_outcome(/* std::current_exception() */); + return make_exceptional_outcome/**/(/* std::current_exception() */); } } ~~~ @@ -322,11 +339,54 @@ as a void version of the same transport, preserving any empty/errored/excepted s was valued, the returned copy will be valued **void**.
+Outcome's refinements do not permit `T` to be constructible from an `error_code_extended` +or `std::exception_ptr` and vice versa for much improved compile times. This allows us +to offer implicit construction from all three types, so you can entirely avoid any of the +`make_xxx()` functions just described and just return the state you desire directly. + +We have however been using these in our own code for two years now, and we recommend that +you always use the `make_xxx()` functions in code intended for a long life span +because they make code correctness auditing so much easier - with a single glance you can +tell a function's error handling is correct or not. If the code +is written to rely on the implicit construction, any function of any complexity requires in +depth study to determine correctness. + +All that just said, in a small function, particularly in boilerplate functions, it's +enormously less cluttered to not have to write `make_xxx()` all the time. So choose which +form you use carefully on a function by function basis. + +Finally, it may not be obvious that the above syntax also allows contract programming e.g. this is a style used throughout +AFIO v2 which proven to be very useful for self-documenting the function's contract with +the caller: + +~~~{.cpp} +result file_handle::truncate(file_handle::extent_type newsize) noexcept +{ + BOOST_AFIO_LOG_FUNCTION_CALL(_v.fd); + if(ftruncate(_v.fd, newsize) < 0) + return make_errored_result(errno, last190(_path.native())); + if(are_safety_fsyncs_issued()) + ::fsync(_v.fd); // deliberately ignore failure + return make_valued_result(newsize); +} +~~~ + +The paths taken for success and failure are extremely obvious and jump immediately to +the eye. We manually specify the exact result type returned rather than letting Outcome +perform automatic upconversion, partially for improved compile times as we avoid the +upconversion metaprogramming, but also because in a longer function the exact type +being returned is usually off the top of the screen, and manually specifying it is +useful documentation. Obviously each code base will be different, but consider using the +style above if code correctness and fast auditing is particularly important to you for +a project you expect to be maintaining for many years. + +

\section outcome_macros Outcome's helper macros -We've already seen in part B the helper macro `BOOST_OUTCOME_TRY(var, expr)` which also works +We have already seen in the previous part of this tutorial that the helper macro +`BOOST_OUTCOME_TRY(var, expr)` which also works with `expected` when the error type in the returned Expected is the same. Something unique to Outcome's refinements due to using `error_code_extended` is the convenience macro `BOOST_OUTCOME_CATCH_EXCEPTION_TO_RESULT` which is a long @@ -381,9 +441,12 @@ catch(const std::exception &e) ~~~ This macro is particularly useful when you are calling into the STL from a noexcept -function which returns a `result` and not an `outcome`. So long as the code you +function (e.g. "island of exception throw in a sea of noexcept") which returns a +`result` and not an `outcome`. So long as the code you call only **ever** will throw STL exception types, using this macro is safe and information -loss free. Note that the above sequence does not include a catch all clause, so if +loss free, plus some compiler optimisers will elide the costly exception throw and catch +machinery and replace it with a simple return of the result, thus effectively doing "de-exception-throw" +to the C++ STL which is very, very useful. Note that the above sequence does not include a catch all clause, so if you want one of those then use the `BOOST_OUTCOME_CATCH_ALL_EXCEPTION_TO_RESULT` macro which adds to the end of the catch sequence: @@ -456,10 +519,10 @@ public API with the signature: outcome::expected> execute(std::function f) noexcept; ~~~ This is a nested Expected used to transport one of two unexpected values. In real -world usage of Expected you'll find yourself writing this more than you'd prefer +world usage of Expected you'll find yourself writing this more than you'd prefer, and indeed a historical edition of the Expected proposal had special convenience semantics for them. The current proposal does not however, so you end up writing -clunky code. +clunky code, which isn't necessary with Outcome's refinements. Indeed, it would be worse again if it weren't for the `std::future` being used to carry any exception throws for us which lets us skip a nested Expected. One @@ -468,7 +531,17 @@ simply rethrow any transported exceptions instead of messing around with nested Expected, however the "sea of noexcept" public API design would then be lost and the two examples no longer equivalent. -To conclude, this aspect of simplifying the programmer's effort to write +Another thing which may or may not seem neat to you is that in the Outcome edition, +`outcome` is errored not excepted when it was a known C++ exception type, and +only excepted if it was an unknown C++ exception throw. This is a very powerful +segmentation in practice because it lets you separate the truly unexpected and +unknown failures from the less serious ones. One can therefore employ an abort +on the truly unknown failure strategy quite like Rust does with its `panic!` +approach, yet retain normal C++ exception throws and unwinds where the failure +is not as unknown. Lots of design flexibility and potential lies here, it all +depends on your design and your code base. + +To conclude, this aspect of simplifying the programmer's effort to write various "sea of noexcept" API designs is precisely what Outcome's refinements are intended for. If Outcome's refinements suit well your code base, they should -let you write clearer, more maintainable and less buggy code. *Buen provecho!* +let you write clearer, less verbose, more maintainable and less buggy code. *Buen provecho!* diff --git a/doc/md/08-expectedsynopsis.md b/doc/md/08-expectedsynopsis.md index a769c5ba84..f1b96a8cb2 100644 --- a/doc/md/08-expectedsynopsis.md +++ b/doc/md/08-expectedsynopsis.md @@ -18,9 +18,7 @@ As you will note, there are technically speaking quite a lot of deviations. Most and will present no effect in code using Expected. Occasionally a function is missing or implemented significantly differently. If it has a significantly different signature, it is usually because we feel the LEWG Expected is defective in that area (e.g. the use of `decay<>` for the factory functions -precludes manufacturing `expected` which we have found to be in practice very useful). If -it is missing, it is either because we feel its presence is a defect in the LEWG Expected or we think -it not worth implementing. +precludes manufacturing `expected` which we have found to be in practice very useful). Some of Outcome's Expected deviations from P0323R1 have entered P0323R2 which will be presented at the Toronto WG21 meeting in July 2017. Once P0323R2 has been published, Outcome's Expected @@ -63,16 +61,23 @@ removed from the next version of the proposal due to it conferring little value. we believe the LEWG ones to be defective in various ways. This topic will be discussed in Toronto and reconciliation later is highly likely. - Our `value_or()` member functions pass through the reference rather than returning by -value (which we don't understand why the LEWG proposal does). +value (we don't understand why the LEWG proposal does except that `std::optional` +does, which itself is a bad design choice and it should be changed). +- Rather than `void`, our `value_type` and `error_type` typedefs are set to a descriptive +compiler error generating type if the Expected is configured with `void`. If you want +to know if no type was configured, use the static constexpr bools at +expected::has_value_type and expected::has_error_type +or use `raw_value_type` and `raw_error_type`. The reason for this deviation is to +make metaprogramming using Outcome's transports much easier and less error prone. - Our Expected always defines the default, copy and move constructors even if the the type configured is not capable of it. That means `std::is_copy_constructible` etc returns true when they should return false. The reason why is again to significantly improve compile times by hugely reducing the number of templates which need to be instantiated during routine basic_monad usage, and again this won't be fixed. Instead use the static constexpr bools at: - -
expected::is_default_constructible
- -
expected::is_copy_constructible
- -
expected::is_move_constructible
+ - expected::is_default_constructible + - expected::is_copy_constructible + - expected::is_move_constructible \note Depending on what any Boost peer review thinks, we may inject correct answers for the type traits for basic_monad into namespace std. diff --git a/example/expected_try1.cpp b/example/expected_try1.cpp index 5c2ca0190a..2e1ec623a9 100644 --- a/example/expected_try1.cpp +++ b/example/expected_try1.cpp @@ -25,7 +25,7 @@ using MathResult2 = outcome::expected; MathResult1 div(double x, double y) noexcept { - if (::fabs(y) < FLT_EPSILON) + if (::fabs(y) < DBL_EPSILON) { // This operation would fail, instead let's return the reason of // the failure wrapped in E diff --git a/example/expected_try2.cpp b/example/expected_try2.cpp index 45b0fcd2ec..b37253324d 100644 --- a/example/expected_try2.cpp +++ b/example/expected_try2.cpp @@ -140,7 +140,7 @@ namespace std outcome::expected div(double x, double y) noexcept { - if (::fabs(y) < FLT_EPSILON) + if (::fabs(y) < DBL_EPSILON) { // This operation would fail, instead let's return the reason of // the failure wrapped in E diff --git a/example/expected_try3.cpp b/example/expected_try3.cpp index 5a2db7d90c..84c31180f3 100644 --- a/example/expected_try3.cpp +++ b/example/expected_try3.cpp @@ -142,7 +142,7 @@ namespace std outcome::expected div(double x, double y) noexcept { - if (::fabs(y) < FLT_EPSILON) + if (::fabs(y) < DBL_EPSILON) { // This operation would fail, instead let's return the reason of // the failure wrapped in E diff --git a/include/boost/outcome/outcome_v1.0.hpp b/include/boost/outcome/outcome_v1.0.hpp index 6d1294731d..d579ac9ebb 100644 --- a/include/boost/outcome/outcome_v1.0.hpp +++ b/include/boost/outcome/outcome_v1.0.hpp @@ -1009,9 +1009,9 @@ extern "C" void _mm_pause(); #define BOOST_OUTCOME_V1_ERROR_CODE_IMPL std -#define BOOST_OUTCOME_PREVIOUS_COMMIT_REF f661ee8303496a77adcaa09aca4670f27b6edaad -#define BOOST_OUTCOME_PREVIOUS_COMMIT_DATE "2017-05-10 11:02:35 +00:00" -#define BOOST_OUTCOME_PREVIOUS_COMMIT_UNIQUE f661ee83 +#define BOOST_OUTCOME_PREVIOUS_COMMIT_REF 9274c0d42307cac597f7c4e07a7eb9000a4792a5 +#define BOOST_OUTCOME_PREVIOUS_COMMIT_DATE "2017-05-10 19:35:33 +00:00" +#define BOOST_OUTCOME_PREVIOUS_COMMIT_UNIQUE 9274c0d4 #define BOOST_OUTCOME_V1 (boost), (outcome), (BOOSTLITE_BIND_NAMESPACE_VERSION(, BOOST_OUTCOME_NAMESPACE_VERSION, BOOST_OUTCOME_V1_STL11_IMPL, BOOST_OUTCOME_V1_ERROR_CODE_IMPL, BOOST_OUTCOME_PREVIOUS_COMMIT_UNIQUE), inline) @@ -1184,7 +1184,7 @@ using ::std::generic_category; } } } } #endif -namespace boost { namespace outcome { inline namespace _1_0_std_std_f661ee83 { +namespace boost { namespace outcome { inline namespace _1_0_std_std_9274c0d4 { namespace stl11 { using namespace boost_lite::bind::std::system_error; @@ -1451,7 +1451,7 @@ _Check_return_ _Ret_writes_maybenull_(len) char **backtrace_symbols(_In_reads_(l #define BOOST_OUTCOME_THROW(expr) throw expr #else #include -namespace boost { namespace outcome { inline namespace _1_0_std_std_f661ee83 { +namespace boost { namespace outcome { inline namespace _1_0_std_std_9274c0d4 { namespace detail { BOOSTLITE_NORETURN inline void do_fatal_exit(const char *expr) @@ -2332,7 +2332,7 @@ namespace ringbuffer_log #define BOOST_OUTCOME_DEFAULT_EXTENDED_ERROR_CODE_LOG_SIZE 4096 #endif -namespace boost { namespace outcome { inline namespace _1_0_std_std_f661ee83 { +namespace boost { namespace outcome { inline namespace _1_0_std_std_9274c0d4 { inline boost_lite::ringbuffer_log::simple_ringbuffer_log &extended_error_code_log() @@ -2510,7 +2510,7 @@ inline std::ostream &operator<<(std::ostream &s, const error_code_extended &ec) -namespace boost { namespace outcome { inline namespace _1_0_std_std_f661ee83 { +namespace boost { namespace outcome { inline namespace _1_0_std_std_9274c0d4 { enum class monad_errc @@ -2596,11 +2596,11 @@ inline stl11::error_condition make_error_condition(monad_errc e) namespace std { - template <> struct is_error_code_enum : std::true_type + template <> struct is_error_code_enum : std::true_type { }; - template <> struct is_error_condition_enum : std::true_type + template <> struct is_error_condition_enum : std::true_type { }; } @@ -2612,7 +2612,7 @@ namespace std -namespace boost { namespace outcome { inline namespace _1_0_std_std_f661ee83 { +namespace boost { namespace outcome { inline namespace _1_0_std_std_9274c0d4 { struct empty_t @@ -3954,9 +3954,9 @@ class value_storage : public std::conditional inline istream &operator>>(istream &s, boost ::outcome ::_1_0_std_std_f661ee83::value_storage<_value_type, _error_type, _exception_type> &v) + template inline istream &operator>>(istream &s, boost ::outcome ::_1_0_std_std_9274c0d4::value_storage<_value_type, _error_type, _exception_type> &v) { - using namespace boost ::outcome ::_1_0_std_std_f661ee83; + using namespace boost ::outcome ::_1_0_std_std_9274c0d4; switch(v.type) { case value_storage<_value_type, _error_type, _exception_type>::storage_type::value: @@ -3966,9 +3966,9 @@ namespace std } } - template inline ostream &operator<<(ostream &s, const boost ::outcome ::_1_0_std_std_f661ee83::value_storage<_value_type, void, void> &v) + template inline ostream &operator<<(ostream &s, const boost ::outcome ::_1_0_std_std_9274c0d4::value_storage<_value_type, void, void> &v) { - using namespace boost ::outcome ::_1_0_std_std_f661ee83; + using namespace boost ::outcome ::_1_0_std_std_9274c0d4; using _error_type = void; using _exception_type = void; switch(v.type) @@ -3981,9 +3981,9 @@ namespace std return s << "(unknown)"; } } - template inline ostream &operator<<(ostream &s, const boost ::outcome ::_1_0_std_std_f661ee83::value_storage<_value_type, _error_type, void> &v) + template inline ostream &operator<<(ostream &s, const boost ::outcome ::_1_0_std_std_9274c0d4::value_storage<_value_type, _error_type, void> &v) { - using namespace boost ::outcome ::_1_0_std_std_f661ee83; + using namespace boost ::outcome ::_1_0_std_std_9274c0d4; using _exception_type = void; switch(v.type) { @@ -3997,9 +3997,9 @@ namespace std return s << "(unknown)"; } } - template inline ostream &operator<<(ostream &s, const boost ::outcome ::_1_0_std_std_f661ee83::value_storage<_value_type, _error_type, _exception_type> &v) + template inline ostream &operator<<(ostream &s, const boost ::outcome ::_1_0_std_std_9274c0d4::value_storage<_value_type, _error_type, _exception_type> &v) { - using namespace boost ::outcome ::_1_0_std_std_f661ee83; + using namespace boost ::outcome ::_1_0_std_std_9274c0d4; switch(v.type) { case value_storage<_value_type, _error_type, _exception_type>::storage_type::empty: @@ -4123,7 +4123,7 @@ namespace std } #endif -namespace boost { namespace outcome { inline namespace _1_0_std_std_f661ee83 { +namespace boost { namespace outcome { inline namespace _1_0_std_std_9274c0d4 { template class basic_monad; @@ -6894,7 +6894,7 @@ template inline expected as_void(const expected inline void swap(boost ::outcome ::_1_0_std_std_f661ee83::basic_monad &a, boost ::outcome ::_1_0_std_std_f661ee83::basic_monad &b) { a.swap(b); } + template inline void swap(boost ::outcome ::_1_0_std_std_9274c0d4::basic_monad &a, boost ::outcome ::_1_0_std_std_9274c0d4::basic_monad &b) { a.swap(b); } } #define BOOST_OUTCOME__GLUE2(x, y) x##y diff --git a/include/boost/outcome/revision.hpp b/include/boost/outcome/revision.hpp index ede7252692..1f93855457 100644 --- a/include/boost/outcome/revision.hpp +++ b/include/boost/outcome/revision.hpp @@ -1,4 +1,4 @@ // Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time -#define BOOST_OUTCOME_PREVIOUS_COMMIT_REF f661ee8303496a77adcaa09aca4670f27b6edaad -#define BOOST_OUTCOME_PREVIOUS_COMMIT_DATE "2017-05-10 11:02:35 +00:00" -#define BOOST_OUTCOME_PREVIOUS_COMMIT_UNIQUE f661ee83 +#define BOOST_OUTCOME_PREVIOUS_COMMIT_REF 9274c0d42307cac597f7c4e07a7eb9000a4792a5 +#define BOOST_OUTCOME_PREVIOUS_COMMIT_DATE "2017-05-10 19:35:33 +00:00" +#define BOOST_OUTCOME_PREVIOUS_COMMIT_UNIQUE 9274c0d4