@@ -515,25 +515,97 @@ class Unexpected
515
515
516
516
template <class E > Unexpected (E) -> Unexpected<E>;
517
517
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
+
518
567
#ifndef MRDOCS_TRY
519
568
# define MRDOCS_MERGE_ (a, b ) a##b
520
569
# define MRDOCS_LABEL_ (a ) MRDOCS_MERGE_(expected_result_, a)
521
570
# define MRDOCS_UNIQUE_NAME MRDOCS_LABEL_ (__LINE__)
571
+
572
+ // / Try to retrive expected-like type
522
573
# define MRDOCS_TRY_VOID (expr ) \
523
574
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 )); \
526
577
} \
527
578
void (0 )
528
579
# define MRDOCS_TRY_VAR (var, expr ) \
529
580
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
+ } \
533
584
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
535
592
# 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__)
537
609
#endif
538
610
539
611
@@ -1854,6 +1926,36 @@ class Expected<T, E>
1854
1926
: unex_(std::move(u).error()), has_value_(false )
1855
1927
{ }
1856
1928
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
+
1857
1959
constexpr explicit
1858
1960
Expected (std::in_place_t ) noexcept
1859
1961
: Expected()
0 commit comments