Skip to content
This repository was archived by the owner on May 3, 2026. It is now read-only.

Commit d8837c3

Browse files
committed
move is_result traits into traits namespace
1 parent f9fc447 commit d8837c3

1 file changed

Lines changed: 20 additions & 336 deletions

File tree

include/common/result.hpp

Lines changed: 20 additions & 336 deletions
Original file line numberDiff line numberDiff line change
@@ -126,19 +126,39 @@ template<typename T, traits::IsResultError... Errs>
126126
requires(sizeof...(Errs) > 0)
127127
class Result;
128128

129+
namespace traits {
130+
129131
/**
130132
* @brief Type trait to check if a type is a Result.
131133
* @tparam T Type to check.
132134
*/
133135
template<typename>
134136
struct is_result : std::false_type {};
135137

138+
/**
139+
* @brief Type trait to check if a type is a Result.
140+
* @tparam T Type to check.
141+
*/
136142
template<typename T, typename... Errs>
137143
struct is_result<Result<T, Errs...>> : std::true_type {};
138144

145+
/**
146+
* @brief Check whether a type is a Result
147+
* @tparam T Type to check
148+
*/
139149
template<typename T>
140150
inline constexpr bool is_result_v = is_result<T>::value;
141151

152+
/**
153+
* @brief Concept to check if a type is a Result
154+
*
155+
* @tparam T
156+
*/
157+
template<typename T>
158+
concept IsResult = is_result_v<T>;
159+
160+
} // namespace traits
161+
142162
/**
143163
* @brief Result class for expected value or error handling (similar to std::expected).
144164
* @tparam T Type of the expected value.
@@ -255,174 +275,6 @@ class Result {
255275
return !std::holds_alternative<std::monostate>(m_error);
256276
}
257277

258-
// and_then: lvalue
259-
template<typename Fn>
260-
auto and_then(Fn&& f) & {
261-
using ResultType = std::invoke_result_t<Fn, T>;
262-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
263-
264-
if (has_error()) {
265-
return std::visit([](auto&& err) -> ResultType {
266-
return ResultType(std::forward<decltype(err)>(err));
267-
}, m_error);
268-
} else {
269-
return f(m_value);
270-
}
271-
}
272-
273-
// and_then: const lvalue
274-
template<typename Fn>
275-
auto and_then(Fn&& f) const& {
276-
using ResultType = std::invoke_result_t<Fn, const T&>;
277-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
278-
279-
if (has_error()) {
280-
return std::visit([](auto&& err) -> ResultType {
281-
return ResultType(std::forward<decltype(err)>(err));
282-
}, m_error);
283-
} else {
284-
return f(m_value);
285-
}
286-
}
287-
288-
// and_then: rvalue
289-
template<typename Fn>
290-
auto and_then(Fn&& f) && {
291-
using ResultType = std::invoke_result_t<Fn, T&&>;
292-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
293-
294-
if (has_error()) {
295-
return std::visit([](auto&& err) -> ResultType {
296-
return ResultType(std::forward<decltype(err)>(err));
297-
}, std::move(m_error));
298-
} else {
299-
return f(std::move(m_value));
300-
}
301-
}
302-
303-
// and_then: const rvalue
304-
template<typename Fn>
305-
auto and_then(Fn&& f) const&& {
306-
using ResultType = std::invoke_result_t<Fn, const T&&>;
307-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
308-
309-
if (has_error()) {
310-
return std::visit([](auto&& err) -> ResultType {
311-
return ResultType(std::forward<decltype(err)>(err));
312-
}, std::move(m_error));
313-
} else {
314-
return f(std::move(m_value));
315-
}
316-
}
317-
318-
// or_else: lvalue
319-
template<typename Fn>
320-
auto or_else(Fn&& f) & {
321-
if (!has_error()) {
322-
return *this;
323-
}
324-
325-
return std::visit([&f](auto&& err) {
326-
return f(std::forward<decltype(err)>(err));
327-
}, m_error);
328-
}
329-
330-
// or_else: const lvalue
331-
template<typename Fn>
332-
auto or_else(Fn&& f) const& {
333-
if (!has_error()) {
334-
return *this;
335-
}
336-
337-
return std::visit([&f](auto&& err) {
338-
return f(std::forward<decltype(err)>(err));
339-
}, m_error);
340-
}
341-
342-
// or_else: rvalue
343-
template<typename Fn>
344-
auto or_else(Fn&& f) && {
345-
if (!has_error()) {
346-
return std::move(*this);
347-
}
348-
349-
return std::visit([&f](auto&& err) {
350-
return f(std::forward<decltype(err)>(err));
351-
}, std::move(m_error));
352-
}
353-
354-
// or_else: const rvalue
355-
template<typename Fn>
356-
auto or_else(Fn&& f) const&& {
357-
if (!has_error()) {
358-
return std::move(*this);
359-
}
360-
361-
return std::visit([&f](auto&& err) {
362-
return f(std::forward<decltype(err)>(err));
363-
}, std::move(m_error));
364-
}
365-
366-
// transform: lvalue
367-
template<typename Fn>
368-
auto transform(Fn&& f) & {
369-
using U = std::invoke_result_t<Fn, T>;
370-
using ResultType = Result<U, Errs...>;
371-
372-
if (has_error()) {
373-
return std::visit([](auto&& err) -> ResultType {
374-
return ResultType(std::forward<decltype(err)>(err));
375-
}, m_error);
376-
} else {
377-
return ResultType(f(m_value));
378-
}
379-
}
380-
381-
// transform: const lvalue
382-
template<typename Fn>
383-
auto transform(Fn&& f) const& {
384-
using U = std::invoke_result_t<Fn, const T&>;
385-
using ResultType = Result<U, Errs...>;
386-
387-
if (has_error()) {
388-
return std::visit([](auto&& err) -> ResultType {
389-
return ResultType(std::forward<decltype(err)>(err));
390-
}, m_error);
391-
} else {
392-
return ResultType(f(m_value));
393-
}
394-
}
395-
396-
// transform: rvalue
397-
template<typename Fn>
398-
auto transform(Fn&& f) && {
399-
using U = std::invoke_result_t<Fn, T&&>;
400-
using ResultType = Result<U, Errs...>;
401-
402-
if (has_error()) {
403-
return std::visit([](auto&& err) -> ResultType {
404-
return ResultType(std::forward<decltype(err)>(err));
405-
}, std::move(m_error));
406-
} else {
407-
return ResultType(f(std::move(m_value)));
408-
}
409-
}
410-
411-
// transform: const rvalue
412-
template<typename Fn>
413-
auto transform(Fn&& f) const&& {
414-
using U = std::invoke_result_t<Fn, const T&&>;
415-
using ResultType = Result<U, Errs...>;
416-
417-
if (has_error()) {
418-
return std::visit([](auto&& err) -> ResultType {
419-
return ResultType(std::forward<decltype(err)>(err));
420-
}, std::move(m_error));
421-
} else {
422-
return ResultType(f(std::move(m_value)));
423-
}
424-
}
425-
426278
constexpr operator T&() & {
427279
return m_value;
428280
}
@@ -537,174 +389,6 @@ class Result<void, Errs...> {
537389
return !std::holds_alternative<std::monostate>(m_error);
538390
}
539391

540-
// and_then: lvalue
541-
template<typename Fn>
542-
auto and_then(Fn&& f) & {
543-
using ResultType = std::invoke_result_t<Fn>;
544-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
545-
546-
if (has_error()) {
547-
return std::visit([](auto&& err) -> ResultType {
548-
return ResultType(std::forward<decltype(err)>(err));
549-
}, m_error);
550-
} else {
551-
return f();
552-
}
553-
}
554-
555-
// and_then: const lvalue
556-
template<typename Fn>
557-
auto and_then(Fn&& f) const& {
558-
using ResultType = std::invoke_result_t<Fn>;
559-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
560-
561-
if (has_error()) {
562-
return std::visit([](auto&& err) -> ResultType {
563-
return ResultType(std::forward<decltype(err)>(err));
564-
}, m_error);
565-
} else {
566-
return f();
567-
}
568-
}
569-
570-
// and_then: rvalue
571-
template<typename Fn>
572-
auto and_then(Fn&& f) && {
573-
using ResultType = std::invoke_result_t<Fn>;
574-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
575-
576-
if (has_error()) {
577-
return std::visit([](auto&& err) -> ResultType {
578-
return ResultType(std::forward<decltype(err)>(err));
579-
}, std::move(m_error));
580-
} else {
581-
return f();
582-
}
583-
}
584-
585-
// and_then: const rvalue
586-
template<typename Fn>
587-
auto and_then(Fn&& f) const&& {
588-
using ResultType = std::invoke_result_t<Fn>;
589-
static_assert(is_result_v<ResultType>, "Fn must return a Result type");
590-
591-
if (has_error()) {
592-
return std::visit([](auto&& err) -> ResultType {
593-
return ResultType(std::forward<decltype(err)>(err));
594-
}, std::move(m_error));
595-
} else {
596-
return f();
597-
}
598-
}
599-
600-
// or_else: lvalue
601-
template<typename Fn>
602-
auto or_else(Fn&& f) & {
603-
if (!has_error()) {
604-
return *this;
605-
}
606-
607-
return std::visit([&f](auto&& err) {
608-
return f(std::forward<decltype(err)>(err));
609-
}, m_error);
610-
}
611-
612-
// or_else: const lvalue
613-
template<typename Fn>
614-
auto or_else(Fn&& f) const& {
615-
if (!has_error()) {
616-
return *this;
617-
}
618-
619-
return std::visit([&f](auto&& err) {
620-
return f(std::forward<decltype(err)>(err));
621-
}, m_error);
622-
}
623-
624-
// or_else: rvalue
625-
template<typename Fn>
626-
auto or_else(Fn&& f) && {
627-
if (!has_error()) {
628-
return std::move(*this);
629-
}
630-
631-
return std::visit([&f](auto&& err) {
632-
return f(std::forward<decltype(err)>(err));
633-
}, std::move(m_error));
634-
}
635-
636-
// or_else: const rvalue
637-
template<typename Fn>
638-
auto or_else(Fn&& f) const&& {
639-
if (!has_error()) {
640-
return std::move(*this);
641-
}
642-
643-
return std::visit([&f](auto&& err) {
644-
return f(std::forward<decltype(err)>(err));
645-
}, std::move(m_error));
646-
}
647-
648-
// transform: lvalue
649-
template<typename Fn>
650-
auto transform(Fn&& f) & {
651-
using U = std::invoke_result_t<Fn>;
652-
using ResultType = Result<U, Errs...>;
653-
654-
if (has_error()) {
655-
return std::visit([](auto&& err) -> ResultType {
656-
return ResultType(std::forward<decltype(err)>(err));
657-
}, m_error);
658-
} else {
659-
return ResultType(f());
660-
}
661-
}
662-
663-
// transform: const lvalue
664-
template<typename Fn>
665-
auto transform(Fn&& f) const& {
666-
using U = std::invoke_result_t<Fn>;
667-
using ResultType = Result<U, Errs...>;
668-
669-
if (has_error()) {
670-
return std::visit([](auto&& err) -> ResultType {
671-
return ResultType(std::forward<decltype(err)>(err));
672-
}, m_error);
673-
} else {
674-
return ResultType(f());
675-
}
676-
}
677-
678-
// transform: rvalue
679-
template<typename Fn>
680-
auto transform(Fn&& f) && {
681-
using U = std::invoke_result_t<Fn>;
682-
using ResultType = Result<U, Errs...>;
683-
684-
if (has_error()) {
685-
return std::visit([](auto&& err) -> ResultType {
686-
return ResultType(std::forward<decltype(err)>(err));
687-
}, std::move(m_error));
688-
} else {
689-
return ResultType(f());
690-
}
691-
}
692-
693-
// transform: const rvalue
694-
template<typename Fn>
695-
auto transform(Fn&& f) const&& {
696-
using U = std::invoke_result_t<Fn>;
697-
using ResultType = Result<U, Errs...>;
698-
699-
if (has_error()) {
700-
return std::visit([](auto&& err) -> ResultType {
701-
return ResultType(std::forward<decltype(err)>(err));
702-
}, std::move(m_error));
703-
} else {
704-
return ResultType(f());
705-
}
706-
}
707-
708392
private:
709393
// instead of wrapping the variant in std::optional, we can use std::monostate
710394
std::variant<std::monostate, Errs...> m_error; ///< Variant holding an error or monostate.

0 commit comments

Comments
 (0)