@@ -515,25 +515,97 @@ class Unexpected
515515
516516template <class E > Unexpected (E) -> Unexpected<E>;
517517
518+ namespace detail
519+ {
520+ template <class T >
521+ constexpr
522+ bool
523+ failed (T const &t)
524+ {
525+ if constexpr (isExpected<std::decay_t <T>>)
526+ {
527+ return !t;
528+ }
529+ else if constexpr (std::same_as<std::decay_t <T>, Error>)
530+ {
531+ return t.failed ();
532+ }
533+ else if constexpr (requires (T const & t0) { t0.empty (); })
534+ {
535+ return t.empty ();
536+ }
537+ else if constexpr (std::constructible_from<bool , T>)
538+ {
539+ return !t;
540+ }
541+ }
542+
543+ template <class T >
544+ constexpr
545+ decltype (auto )
546+ error (T const & t)
547+ {
548+ if constexpr (isExpected<std::decay_t <T>>)
549+ {
550+ return t.error ();
551+ }
552+ else if constexpr (std::same_as<std::decay_t <T>, Error>)
553+ {
554+ return t;
555+ }
556+ else if constexpr (requires (T const & t0) { t0.empty (); })
557+ {
558+ return Error (" Empty value" );
559+ }
560+ else if constexpr (std::constructible_from<bool , T>)
561+ {
562+ return Error (" Invalid value" );
563+ }
564+ }
565+ }
566+
518567#ifndef MRDOCS_TRY
519568# define MRDOCS_MERGE_ (a, b ) a##b
520569# define MRDOCS_LABEL_ (a ) MRDOCS_MERGE_(expected_result_, a)
521570# define MRDOCS_UNIQUE_NAME MRDOCS_LABEL_ (__LINE__)
571+
572+ // / Try to retrive expected-like type
522573# define MRDOCS_TRY_VOID (expr ) \
523574 auto MRDOCS_UNIQUE_NAME = expr; \
524- if (! MRDOCS_UNIQUE_NAME) { \
525- return Unexpected (MRDOCS_UNIQUE_NAME. error ()); \
575+ if (detail::failed( MRDOCS_UNIQUE_NAME)) { \
576+ return Unexpected (detail:: error (MRDOCS_UNIQUE_NAME )); \
526577 } \
527578 void (0 )
528579# define MRDOCS_TRY_VAR (var, expr ) \
529580 auto MRDOCS_UNIQUE_NAME = expr; \
530- if (! MRDOCS_UNIQUE_NAME) { \
531- return Unexpected (MRDOCS_UNIQUE_NAME. error ()); \
532- } \
581+ if (detail::failed( MRDOCS_UNIQUE_NAME)) { \
582+ return Unexpected (detail:: error (MRDOCS_UNIQUE_NAME )); \
583+ } \
533584 var = *std::move (MRDOCS_UNIQUE_NAME)
534- # define GET_MACRO (_1, _2, NAME, ...) NAME
585+ # define MRDOCS_TRY_MSG (var, expr, msg ) \
586+ auto MRDOCS_UNIQUE_NAME = expr; \
587+ if (detail::failed(MRDOCS_UNIQUE_NAME)) { \
588+ return Unexpected (Error (msg)); \
589+ } \
590+ var = *std::move (MRDOCS_UNIQUE_NAME)
591+ # define MRDOCS_TRY_GET_MACRO (_1, _2, _3, NAME, ...) NAME
535592# define MRDOCS_TRY (...) \
536- GET_MACRO (__VA_ARGS__, MRDOCS_TRY_VAR, MRDOCS_TRY_VOID)(__VA_ARGS__)
593+ MRDOCS_TRY_GET_MACRO (__VA_ARGS__, MRDOCS_TRY_MSG, MRDOCS_TRY_VAR, MRDOCS_TRY_VOID)(__VA_ARGS__)
594+
595+ // / Check existing expected-like type
596+ # define MRDOCS_CHECK_VOID (var ) \
597+ if (!detail::failed(var)) { \
598+ return Unexpected (detail::error (var)); \
599+ } \
600+ void (0 )
601+ # define MRDOCS_CHECK_MSG (var, msg ) \
602+ if (detail::failed(var)) { \
603+ return Unexpected (Error (msg)); \
604+ } \
605+ void (0 )
606+ # define MRDOCS_CHECK_GET_MACRO (_1, _2, NAME, ...) NAME
607+ # define MRDOCS_CHECK (...) \
608+ MRDOCS_CHECK_GET_MACRO (__VA_ARGS__, MRDOCS_CHECK_MSG, MRDOCS_CHECK_VOID)(__VA_ARGS__)
537609#endif
538610
539611
@@ -1854,6 +1926,36 @@ class Expected<T, E>
18541926 : unex_(std::move(u).error()), has_value_(false )
18551927 { }
18561928
1929+ // The following constructors are extensions that allow
1930+ // Expected to be constructed directly from an error type
1931+ // if this is not ambiguous with the value type. This
1932+ // is not part of std::expected. MRDOCS_EXPECTED_FROM_ERROR
1933+ // can be defined to disable this behavior.
1934+ #ifndef MRDOCS_EXPECTED_FROM_ERROR
1935+ template <class G = E>
1936+ requires
1937+ std::is_constructible_v<E, const G&> &&
1938+ (!std::is_constructible_v<T, const G&>)
1939+ constexpr
1940+ explicit (!std::is_convertible_v<const G&, E>)
1941+ Expected(const G& u)
1942+ noexcept (std::is_nothrow_constructible_v<E, const G&>)
1943+ : unex_(u)
1944+ , has_value_(false )
1945+ { }
1946+
1947+ template <class G = E>
1948+ requires
1949+ std::is_constructible_v<E, G> &&
1950+ (!std::is_constructible_v<T, G>)
1951+ constexpr
1952+ explicit (!std::is_convertible_v<G, E>)
1953+ Expected(G&& u)
1954+ noexcept (std::is_nothrow_constructible_v<E, G>)
1955+ : unex_(std::move(u)), has_value_(false )
1956+ { }
1957+ #endif
1958+
18571959 constexpr explicit
18581960 Expected (std::in_place_t ) noexcept
18591961 : Expected()
0 commit comments