add expected.h (#2)

This commit is contained in:
David Chen
2025-12-21 05:00:54 +08:00
committed by GitHub
parent 540b8dc103
commit 0f41240eeb

98
src/expected.h Normal file
View File

@@ -0,0 +1,98 @@
#ifndef EXPECTED_H
#define EXPECTED_H
#include <exception>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <variant>
struct BadExpectedAccess : std::exception {
const char* what() const noexcept override {
return "bad access to `Expected` without expected value";
}
};
class Unexpected {
public:
explicit Unexpected(std::string_view err_msg) : err_msg_(err_msg) {}
std::string_view error() const noexcept { return err_msg_; }
private:
std::string err_msg_;
};
template <typename T>
class Expected {
static_assert(!std::is_reference_v<T>,
"Expected<T> does not support reference types");
public:
Expected()
requires(std::is_default_constructible_v<T>)
: val_(std::in_place_index<0>) {}
Expected(const T& val) : val_(val) {}
Expected(T&& val) : val_(std::move(val)) {}
Expected(const Unexpected& err) : val_(err) {}
Expected(Unexpected&& err) : val_(std::move(err)) {}
bool has_value() const noexcept { return val_.index() == 0; }
explicit operator bool() const noexcept { return has_value(); }
T& value() & {
if (!has_value()) throw BadExpectedAccess();
return std::get<0>(val_);
}
const T& value() const& {
if (!has_value()) throw BadExpectedAccess();
return std::get<0>(val_);
}
T&& value() && {
if (!has_value()) throw BadExpectedAccess();
return std::move(std::get<0>(val_));
}
const T&& value() const&& {
if (!has_value()) throw BadExpectedAccess();
return std::move(std::get<0>(val_));
}
std::string_view error() const noexcept {
return has_value() ? "" : std::get<1>(val_).error();
}
private:
std::variant<T, Unexpected> val_;
};
template <>
class Expected<void> {
public:
Expected() {}
Expected(const Unexpected& err) : err_(err) {}
Expected(Unexpected&& err) : err_(std::move(err)) {}
bool has_value() const noexcept { return !err_.has_value(); }
explicit operator bool() const noexcept { return has_value(); }
void value() const {
if (!has_value()) throw BadExpectedAccess();
}
std::string_view error() const noexcept {
return err_.has_value() ? err_.value().error() : "";
}
private:
std::optional<Unexpected> err_;
};
#endif // EXPECTED_H