+ //! Move-constructs an `exception_wrapper`
+ //! \post `*this` contains the value of `that` prior to the move
+ //! \post `that.type() == none()`
+ exception_wrapper(exception_wrapper&& that) noexcept;
+
+ //! Copy-constructs an `exception_wrapper`
+ //! \post `*this` contains a copy of `that`, and `that` is unmodified
+ //! \post `type() == that.type()`
+ exception_wrapper(exception_wrapper const& that);
+
+ //! Move-assigns an `exception_wrapper`
+ //! \pre `this != &that`
+ //! \post `*this` contains the value of `that` prior to the move
+ //! \post `that.type() == none()`
+ exception_wrapper& operator=(exception_wrapper&& that) noexcept;
+
+ //! Copy-assigns an `exception_wrapper`
+ //! \post `*this` contains a copy of `that`, and `that` is unmodified
+ //! \post `type() == that.type()`
+ exception_wrapper& operator=(exception_wrapper const& that);
+
+ ~exception_wrapper();
+
+ //! \pre `ptr` is empty, or it holds a reference to an exception that is not
+ //! derived from `std::exception`.
+ //! \post `!ptr || bool(*this)`
+ //! \post `hasThrownException() == true`
+ //! \post `type() == unknown()`
+ explicit exception_wrapper(std::exception_ptr ptr) noexcept;
+
+ //! \pre `ptr` holds a reference to `ex`.
+ //! \post `hasThrownException() == true`
+ //! \post `bool(*this)`
+ //! \post `type() == typeid(ex)`
+ template <class Ex>
+ exception_wrapper(std::exception_ptr ptr, Ex& ex);
+
+ //! \pre `typeid(ex) == typeid(typename decay<Ex>::type)`
+ //! \post `bool(*this)`
+ //! \post `hasThrownException() == false`
+ //! \post `type() == typeid(ex)`
+ //! \note Exceptions of types derived from `std::exception` can be implicitly
+ //! converted to an `exception_wrapper`.
+ template <
+ class Ex,
+ class Ex_ = _t<std::decay<Ex>>,
+ FOLLY_REQUIRES(
+ Conjunction<IsStdException<Ex_>, IsRegularExceptionType<Ex_>>())>
+ /* implicit */ exception_wrapper(Ex&& ex);
+
+ //! \pre `typeid(ex) == typeid(typename decay<Ex>::type)`
+ //! \post `bool(*this)`
+ //! \post `hasThrownException() == false`
+ //! \post `type() == typeid(ex)`
+ //! \note Exceptions of types not derived from `std::exception` can still be
+ //! used to construct an `exception_wrapper`, but you must specify
+ //! `folly::in_place` as the first parameter.
+ template <
+ class Ex,
+ class Ex_ = _t<std::decay<Ex>>,
+ FOLLY_REQUIRES(IsRegularExceptionType<Ex_>())>
+ exception_wrapper(in_place_t, Ex&& ex);
+
+ //! Swaps the value of `*this` with the value of `that`
+ void swap(exception_wrapper& that) noexcept;
+
+ //! \return `true` if `*this` is not holding an exception.
+ explicit operator bool() const noexcept;
+
+ //! \return `!bool(*this)`
+ bool operator!() const noexcept;
+
+ //! Make this `exception_wrapper` empty
+ //! \post `!*this`
+ void reset();
+
+ //! \return `true` if this `exception_wrapper` holds a reference to an
+ //! exception that was thrown (i.e., if it was constructed with
+ //! a `std::exception_ptr`, or if `to_exception_ptr()` was called on a
+ //! (non-const) reference to `*this`).
+ bool has_exception_ptr() const noexcept;
+
+ //! \return a pointer to the `std::exception` held by `*this`, if it holds
+ //! one; otherwise, returns `nullptr`.
+ //! \note This function does not mutate the `exception_wrapper` object.
+ //! \note This function never causes an exception to be thrown.
+ std::exception* get_exception() noexcept;
+ //! \overload
+ std::exception const* get_exception() const noexcept;
+
+ //! \return A `std::exception_ptr` that references either the exception held
+ //! by `*this`, or a copy of same.
+ //! \note This function may need to throw an exception to complete the action.
+ //! \note The non-const overload of this function mutates `*this` to cache the
+ //! computed `std::exception_ptr`; that is, this function may cause
+ //! `has_exception_ptr()` to change from `false` to `true`.
+ std::exception_ptr const& to_exception_ptr() noexcept;
+ //! \overload
+ std::exception_ptr to_exception_ptr() const noexcept;
+
+ //! \return the `typeid` of an unspecified type used by
+ //! `exception_wrapper::type()` to denote an empty `exception_wrapper`.
+ static std::type_info const& none() noexcept;
+ //! \return the `typeid` of an unspecified type used by
+ //! `exception_wrapper::type()` to denote an `exception_wrapper` that
+ //! holds an exception of unknown type.
+ static std::type_info const& unknown() noexcept;
+
+ //! Returns the `typeid` of the wrapped exception object. If there is no
+ //! wrapped exception object, returns `exception_wrapper::none()`. If
+ //! this instance wraps an exception of unknown type not derived from
+ //! `std::exception`, returns `exception_wrapper::unknown()`.
+ std::type_info const& type() const noexcept;
+
+ //! \return If `get_exception() != nullptr`, `class_name() + ": " +
+ //! get_exception()->what()`; otherwise, `class_name()`.
+ folly::fbstring what() const;
+
+ //! \return If `!*this`, the empty string; otherwise, if
+ //! `type() == unknown()`, the string `"<unknown exception>"`; otherwise,
+ //! the result of `type().name()` after demangling.
+ folly::fbstring class_name() const;
+
+ //! \tparam Ex The expression type to check for compatibility with.
+ //! \return `true` if and only if `*this` wraps an exception that would be
+ //! caught with a `catch(Ex const&)` clause.
+ //! \note If `*this` is empty, this function returns `false`.
+ template <class Ex>
+ bool is_compatible_with() const noexcept;
+
+ //! \pre `bool(*this)`
+ //! Throws the wrapped expression.
+ [[noreturn]] void throwException() const;
+
+ //! Call `fn` with the wrapped exception (if any), if `fn` can accept it.
+ //! \par Example
+ //! \code
+ //! exception_wrapper ew{std::runtime_error("goodbye cruel world")};
+ //!
+ //! assert( ew.with_exception([](std::runtime_error& e){/*...*/}) );
+ //!
+ //! assert( !ew.with_exception([](int& e){/*...*/}) );
+ //!
+ //! assert( !exception_wrapper{}.with_exception([](int& e){/*...*/}) );
+ //! \endcode
+ //! \tparam Ex Optionally, the type of the exception that `fn` accepts.
+ //! \tparam Fn The type of a monomophic function object.
+ //! \param fn A function object to call with the wrapped exception
+ //! \return `true` if and only if `fn` was called.
+ //! \note Optionally, you may explicitly specify the type of the exception
+ //! that `fn` expects, as in
+ //! \code
+ //! ew.with_exception<std::runtime_error>([](auto&& e) { /*...*/; });
+ //! \endcode
+ //! \note The handler may or may not be invoked with an active exception.
+ //! **Do not try to rethrow the exception with `throw;` from within your
+ //! handler -- that is, a throw expression with no operand.** This may
+ //! cause your process to terminate. (It is perfectly ok to throw from
+ //! a handler so long as you specify the exception to throw, as in
+ //! `throw e;`.)
+ template <class Ex = void const, class Fn>
+ bool with_exception(Fn fn);
+ //! \overload
+ template <class Ex = void const, class Fn>
+ bool with_exception(Fn fn) const;
+
+ //! Handle the wrapped expression as if with a series of `catch` clauses,
+ //! propagating the exception if no handler matches.
+ //! \par Example
+ //! \code
+ //! exception_wrapper ew{std::runtime_error("goodbye cruel world")};
+ //!
+ //! ew.handle(
+ //! [&](std::logic_error const& e) {
+ //! LOG(DFATAL) << "ruh roh";
+ //! ew.throwException(); // rethrow the active exception without
+ //! // slicing it. Will not be caught by other
+ //! // handlers in this call.
+ //! },
+ //! [&](std::exception const& e) {
+ //! LOG(ERROR) << ew.what();
+ //! });
+ //! \endcode
+ //! In the above example, any exception _not_ derived from `std::exception`
+ //! will be propagated. To specify a catch-all clause, pass a lambda that
+ //! takes a C-style elipses, as in:
+ //! \code
+ //! ew.handle(/*...* /, [](...) { /* handle unknown exception */ } )
+ //! \endcode
+ //! \pre `!*this`
+ //! \tparam CatchFns... A pack of unary monomorphic function object types.
+ //! \param fns A pack of unary monomorphic function objects to be treated as
+ //! an ordered list of potential exception handlers.
+ //! \note The handlers may or may not be invoked with an active exception.
+ //! **Do not try to rethrow the exception with `throw;` from within your
+ //! handler -- that is, a throw expression with no operand.** This may
+ //! cause your process to terminate. (It is perfectly ok to throw from
+ //! a handler so long as you specify the exception to throw, as in
+ //! `throw e;`.)
+ template <class... CatchFns>
+ void handle(CatchFns... fns);
+ //! \overload
+ template <class... CatchFns>
+ void handle(CatchFns... fns) const;