Last active
June 9, 2025 12:29
-
-
Save dk949/7ab26f6405813e246528994e0f560fba to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef UT_ERR | |
#define UT_ERR | |
#include <concepts> | |
#include <type_traits> | |
#if __cplusplus < 202'302L | |
# error this file has to be compiled with at least C++23 | |
#endif | |
#include <expected> | |
#include <format> | |
#include <source_location> | |
namespace ut { | |
namespace detail { | |
template<typename... Args> | |
struct ErrorStringT { | |
std::format_string<Args...> fmt; | |
std::source_location loc; | |
template<std::convertible_to<std::string_view> Str> | |
explicit(false) consteval ErrorStringT(Str const &f, std::source_location l = std::source_location::current()) | |
: fmt(std::format_string<Args...> {f}) | |
, loc(l) { } | |
}; | |
struct EmptyBase { }; | |
template<typename T> | |
struct ErrorPayload { | |
T payload; | |
}; | |
template<typename T> | |
concept Formattable = requires(std::formatter<T> f) { | |
{f}; | |
}; | |
} // namespace detail | |
// This alias is needed to prevent template argument deduction | |
template<typename... Args> | |
using ErrorString = detail::ErrorStringT<std::type_identity_t<Args>...>; | |
template<typename Payload = void, typename Message = std::string> | |
struct BaseError : std::conditional_t<std::same_as<Payload, void>, detail::EmptyBase, detail::ErrorPayload<Payload>> { | |
public: | |
Message msg; | |
private: | |
std::source_location m_loc; | |
public: | |
BaseError(Message m, std::source_location l) requires(std::constructible_from<Message, std::string>) | |
: msg(std::move(m)) | |
, m_loc(l) { } | |
explicit BaseError(Message m, std::source_location l = std::source_location::current()) | |
requires(!std::constructible_from<Message, std::string>) | |
: msg(std::move(m)) | |
, m_loc(l) { } | |
template<typename... Args> | |
explicit BaseError(ErrorString<Args...> fmt, Args &&...args) requires(std::constructible_from<Message, std::string>) | |
: msg(std::format(fmt.fmt, std::forward<Args>(args)...)) | |
, m_loc(fmt.loc) { } | |
[[nodiscard]] | |
std::string format() const requires(detail::Formattable<Message>) { | |
return std::format("({}) {}:{}:{}:\n{}", m_loc.function_name(), m_loc.file_name(), m_loc.line(), m_loc.column(), msg); | |
} | |
[[nodiscard]] | |
std::source_location const &loc() const { | |
return m_loc; | |
} | |
}; | |
using Error = BaseError<>; | |
template<typename T> | |
using ErrorOr = std::expected<T, Error>; | |
template<typename... Args> | |
[[nodiscard]] | |
std::unexpected<BaseError<>> error(ErrorString<Args...> fmt, Args &&...args) { | |
return std::unexpected(Error {fmt, std::forward<Args>(args)...}); | |
} | |
} // namespace ut | |
#endif // UT_ERR |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
convenient error type for use with std::expected |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment