#pragma once #include #include #include #include // Define an error type class Error { public: explicit Error(std::string message) : m_Message(std::move(message)) {} [[nodiscard]] const std::string& message() const { return m_Message; } private: std::string m_Message; }; // Primary template for Result with a default type of void template class Result; // Specialization for Result template <> class Result { public: // Constructors for success and error Result() : m_Result(std::monostate {}) {} Result(const Error& error) : m_Result(error) {} Result(Error&& error) : m_Result(std::move(error)) {} // Check if the result is an error [[nodiscard]] bool isOk() const { return std::holds_alternative(m_Result); } [[nodiscard]] bool isErr() const { return std::holds_alternative(m_Result); } // Throw an exception if it is an error void value() const { if (isErr()) { throw std::logic_error("Attempted to access value of an error Result"); } } // Get the error or throw an exception if it is a value [[nodiscard]] const Error& error() const { if (isOk()) { throw std::logic_error("Attempted to access error of an ok Result"); } return std::get(m_Result); } private: std::variant m_Result; }; // Primary template for Result template class Result { public: // Constructors for success and error Result(const T& value) : m_Result(value) {} Result(T&& value) : m_Result(std::move(value)) {} Result(const Error& error) : m_Result(error) {} Result(Error&& error) : m_Result(std::move(error)) {} // Check if the result is an error [[nodiscard]] bool isOk() const { return std::holds_alternative(m_Result); } [[nodiscard]] bool isErr() const { return std::holds_alternative(m_Result); } // Get the value or throw an exception if it is an error const T& value() const { if (isErr()) { throw std::logic_error("Attempted to access value of an error Result"); } return std::get(m_Result); } // Get the error or throw an exception if it is a value [[nodiscard]] const Error& error() const { if (isOk()) { throw std::logic_error("Attempted to access error of an ok Result"); } return std::get(m_Result); } // Optional: Get the value or provide a default T valueOr(const T& defaultValue) const { return isOk() ? std::get(m_Result) : defaultValue; } private: std::variant m_Result; }; template auto Ok(T&& value) { return Result>(std::forward(value)); } inline auto Ok() { return Result(); }