@@ -83,6 +83,31 @@ class SentinelValue<T> {
8383 static constexpr T value = get(); // /< Precomputed sentinel value for type T.
8484};
8585
86+ // forward declarations
87+ template <typename T, typename ... Errs>
88+ requires (sizeof ...(Errs) > 0 ) && (std::derived_from<Errs, ResultError> && ...)
89+ class Result ;
90+
91+ template <typename ... Errs>
92+ requires (sizeof ...(Errs) > 0 ) && (std::derived_from<Errs, ResultError> && ...)
93+ class Result <void , Errs...>;
94+
95+ /* *
96+ * @brief Type trait to check if a type is a Result.
97+ * @tparam T Type to check.
98+ */
99+ template <typename >
100+ struct is_result : std::false_type {};
101+
102+ template <typename T, typename ... Errs>
103+ struct is_result <Result<T, Errs...>> : std::true_type {};
104+
105+ template <typename ... Errs>
106+ struct is_result <Result<void , Errs...>> : std::true_type {};
107+
108+ template <typename T>
109+ inline constexpr bool is_result_v = is_result<T>::value;
110+
86111/* *
87112 * @brief Result class for expected value or error handling (similar to std::expected).
88113 * @tparam T Type of the expected value.
@@ -196,7 +221,175 @@ class Result {
196221 }
197222
198223 constexpr bool has_error () {
199- return !std::holds_alternative<std::monostate>(m_value);
224+ return !std::holds_alternative<std::monostate>(m_error);
225+ }
226+
227+ // and_then: lvalue
228+ template <typename Fn>
229+ auto and_then (Fn&& f) & {
230+ using ResultType = std::invoke_result_t <Fn, T>;
231+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
232+
233+ if (has_error ()) {
234+ return std::visit ([](auto && err) -> ResultType {
235+ return ResultType (std::forward<decltype (err)>(err));
236+ }, m_error);
237+ } else {
238+ return f (m_value);
239+ }
240+ }
241+
242+ // and_then: const lvalue
243+ template <typename Fn>
244+ auto and_then (Fn&& f) const & {
245+ using ResultType = std::invoke_result_t <Fn, const T&>;
246+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
247+
248+ if (has_error ()) {
249+ return std::visit ([](auto && err) -> ResultType {
250+ return ResultType (std::forward<decltype (err)>(err));
251+ }, m_error);
252+ } else {
253+ return f (m_value);
254+ }
255+ }
256+
257+ // and_then: rvalue
258+ template <typename Fn>
259+ auto and_then (Fn&& f) && {
260+ using ResultType = std::invoke_result_t <Fn, T&&>;
261+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
262+
263+ if (has_error ()) {
264+ return std::visit ([](auto && err) -> ResultType {
265+ return ResultType (std::forward<decltype (err)>(err));
266+ }, std::move (m_error));
267+ } else {
268+ return f (std::move (m_value));
269+ }
270+ }
271+
272+ // and_then: const rvalue
273+ template <typename Fn>
274+ auto and_then (Fn&& f) const && {
275+ using ResultType = std::invoke_result_t <Fn, const T&&>;
276+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
277+
278+ if (has_error ()) {
279+ return std::visit ([](auto && err) -> ResultType {
280+ return ResultType (std::forward<decltype (err)>(err));
281+ }, std::move (m_error));
282+ } else {
283+ return f (std::move (m_value));
284+ }
285+ }
286+
287+ // or_else: lvalue
288+ template <typename Fn>
289+ auto or_else (Fn&& f) & {
290+ if (!has_error ()) {
291+ return *this ;
292+ }
293+
294+ return std::visit ([&f](auto && err) {
295+ return f (std::forward<decltype (err)>(err));
296+ }, m_error);
297+ }
298+
299+ // or_else: const lvalue
300+ template <typename Fn>
301+ auto or_else (Fn&& f) const & {
302+ if (!has_error ()) {
303+ return *this ;
304+ }
305+
306+ return std::visit ([&f](auto && err) {
307+ return f (std::forward<decltype (err)>(err));
308+ }, m_error);
309+ }
310+
311+ // or_else: rvalue
312+ template <typename Fn>
313+ auto or_else (Fn&& f) && {
314+ if (!has_error ()) {
315+ return std::move (*this );
316+ }
317+
318+ return std::visit ([&f](auto && err) {
319+ return f (std::forward<decltype (err)>(err));
320+ }, std::move (m_error));
321+ }
322+
323+ // or_else: const rvalue
324+ template <typename Fn>
325+ auto or_else (Fn&& f) const && {
326+ if (!has_error ()) {
327+ return std::move (*this );
328+ }
329+
330+ return std::visit ([&f](auto && err) {
331+ return f (std::forward<decltype (err)>(err));
332+ }, std::move (m_error));
333+ }
334+
335+ // transform: lvalue
336+ template <typename Fn>
337+ auto transform (Fn&& f) & {
338+ using U = std::invoke_result_t <Fn, T>;
339+ using ResultType = Result<U, Errs...>;
340+
341+ if (has_error ()) {
342+ return std::visit ([](auto && err) -> ResultType {
343+ return ResultType (std::forward<decltype (err)>(err));
344+ }, m_error);
345+ } else {
346+ return ResultType (f (m_value));
347+ }
348+ }
349+
350+ // transform: const lvalue
351+ template <typename Fn>
352+ auto transform (Fn&& f) const & {
353+ using U = std::invoke_result_t <Fn, const T&>;
354+ using ResultType = Result<U, Errs...>;
355+
356+ if (has_error ()) {
357+ return std::visit ([](auto && err) -> ResultType {
358+ return ResultType (std::forward<decltype (err)>(err));
359+ }, m_error);
360+ } else {
361+ return ResultType (f (m_value));
362+ }
363+ }
364+
365+ // transform: rvalue
366+ template <typename Fn>
367+ auto transform (Fn&& f) && {
368+ using U = std::invoke_result_t <Fn, T&&>;
369+ using ResultType = Result<U, Errs...>;
370+
371+ if (has_error ()) {
372+ return std::visit ([](auto && err) -> ResultType {
373+ return ResultType (std::forward<decltype (err)>(err));
374+ }, std::move (m_error));
375+ } else {
376+ return ResultType (f (std::move (m_value)));
377+ }
378+ }
379+
380+ // transform: const rvalue
381+ template <typename Fn>
382+ auto transform (Fn&& f) const && {
383+ using U = std::invoke_result_t <Fn, const T&&>;
384+ using ResultType = Result<U, Errs...>;
385+
386+ if (has_error ()) {
387+ return std::visit ([](auto && err) -> ResultType {
388+ return ResultType (std::forward<decltype (err)>(err));
389+ }, std::move (m_error));
390+ } else {
391+ return ResultType (f (std::move (m_value)));
392+ }
200393 }
201394
202395 constexpr operator T&() & {
@@ -309,6 +502,178 @@ class Result<void, Errs...> {
309502 }
310503 }
311504
505+ constexpr bool has_error () {
506+ return !std::holds_alternative<std::monostate>(m_error);
507+ }
508+
509+ // and_then: lvalue
510+ template <typename Fn>
511+ auto and_then (Fn&& f) & {
512+ using ResultType = std::invoke_result_t <Fn>;
513+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
514+
515+ if (has_error ()) {
516+ return std::visit ([](auto && err) -> ResultType {
517+ return ResultType (std::forward<decltype (err)>(err));
518+ }, m_error);
519+ } else {
520+ return f ();
521+ }
522+ }
523+
524+ // and_then: const lvalue
525+ template <typename Fn>
526+ auto and_then (Fn&& f) const & {
527+ using ResultType = std::invoke_result_t <Fn>;
528+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
529+
530+ if (has_error ()) {
531+ return std::visit ([](auto && err) -> ResultType {
532+ return ResultType (std::forward<decltype (err)>(err));
533+ }, m_error);
534+ } else {
535+ return f ();
536+ }
537+ }
538+
539+ // and_then: rvalue
540+ template <typename Fn>
541+ auto and_then (Fn&& f) && {
542+ using ResultType = std::invoke_result_t <Fn>;
543+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
544+
545+ if (has_error ()) {
546+ return std::visit ([](auto && err) -> ResultType {
547+ return ResultType (std::forward<decltype (err)>(err));
548+ }, std::move (m_error));
549+ } else {
550+ return f ();
551+ }
552+ }
553+
554+ // and_then: const rvalue
555+ template <typename Fn>
556+ auto and_then (Fn&& f) const && {
557+ using ResultType = std::invoke_result_t <Fn>;
558+ static_assert (is_result_v<ResultType>, " Fn must return a Result type" );
559+
560+ if (has_error ()) {
561+ return std::visit ([](auto && err) -> ResultType {
562+ return ResultType (std::forward<decltype (err)>(err));
563+ }, std::move (m_error));
564+ } else {
565+ return f ();
566+ }
567+ }
568+
569+ // or_else: lvalue
570+ template <typename Fn>
571+ auto or_else (Fn&& f) & {
572+ if (!has_error ()) {
573+ return *this ;
574+ }
575+
576+ return std::visit ([&f](auto && err) {
577+ return f (std::forward<decltype (err)>(err));
578+ }, m_error);
579+ }
580+
581+ // or_else: const lvalue
582+ template <typename Fn>
583+ auto or_else (Fn&& f) const & {
584+ if (!has_error ()) {
585+ return *this ;
586+ }
587+
588+ return std::visit ([&f](auto && err) {
589+ return f (std::forward<decltype (err)>(err));
590+ }, m_error);
591+ }
592+
593+ // or_else: rvalue
594+ template <typename Fn>
595+ auto or_else (Fn&& f) && {
596+ if (!has_error ()) {
597+ return std::move (*this );
598+ }
599+
600+ return std::visit ([&f](auto && err) {
601+ return f (std::forward<decltype (err)>(err));
602+ }, std::move (m_error));
603+ }
604+
605+ // or_else: const rvalue
606+ template <typename Fn>
607+ auto or_else (Fn&& f) const && {
608+ if (!has_error ()) {
609+ return std::move (*this );
610+ }
611+
612+ return std::visit ([&f](auto && err) {
613+ return f (std::forward<decltype (err)>(err));
614+ }, std::move (m_error));
615+ }
616+
617+ // transform: lvalue
618+ template <typename Fn>
619+ auto transform (Fn&& f) & {
620+ using U = std::invoke_result_t <Fn>;
621+ using ResultType = Result<U, Errs...>;
622+
623+ if (has_error ()) {
624+ return std::visit ([](auto && err) -> ResultType {
625+ return ResultType (std::forward<decltype (err)>(err));
626+ }, m_error);
627+ } else {
628+ return ResultType (f ());
629+ }
630+ }
631+
632+ // transform: const lvalue
633+ template <typename Fn>
634+ auto transform (Fn&& f) const & {
635+ using U = std::invoke_result_t <Fn>;
636+ using ResultType = Result<U, Errs...>;
637+
638+ if (has_error ()) {
639+ return std::visit ([](auto && err) -> ResultType {
640+ return ResultType (std::forward<decltype (err)>(err));
641+ }, m_error);
642+ } else {
643+ return ResultType (f ());
644+ }
645+ }
646+
647+ // transform: rvalue
648+ template <typename Fn>
649+ auto transform (Fn&& f) && {
650+ using U = std::invoke_result_t <Fn>;
651+ using ResultType = Result<U, Errs...>;
652+
653+ if (has_error ()) {
654+ return std::visit ([](auto && err) -> ResultType {
655+ return ResultType (std::forward<decltype (err)>(err));
656+ }, std::move (m_error));
657+ } else {
658+ return ResultType (f ());
659+ }
660+ }
661+
662+ // transform: const rvalue
663+ template <typename Fn>
664+ auto transform (Fn&& f) const && {
665+ using U = std::invoke_result_t <Fn>;
666+ using ResultType = Result<U, Errs...>;
667+
668+ if (has_error ()) {
669+ return std::visit ([](auto && err) -> ResultType {
670+ return ResultType (std::forward<decltype (err)>(err));
671+ }, std::move (m_error));
672+ } else {
673+ return ResultType (f ());
674+ }
675+ }
676+
312677 private:
313678 // instead of wrapping the variant in std::optional, we can use std::monostate
314679 std::variant<std::monostate, Errs...> m_error; // /< Variant holding an error or monostate.
0 commit comments