#pragma once #include #include namespace nxst { template class Result { bool ok; alignas(T) alignas(E) unsigned char storage[sizeof(T) > sizeof(E) ? sizeof(T) : sizeof(E)]; Result() = default; public: static Result success(T val) { Result res; res.ok = true; new (res.storage) T(std::move(val)); return res; } static Result failure(E err) { Result res; res.ok = false; new (res.storage) E(std::move(err)); return res; } ~Result() { if (ok) reinterpret_cast(storage)->~T(); else reinterpret_cast(storage)->~E(); } Result(const Result& other) : ok(other.ok) { if (ok) new (storage) T(*reinterpret_cast(other.storage)); else new (storage) E(*reinterpret_cast(other.storage)); } Result(Result&& other) : ok(other.ok) { if (ok) new (storage) T(std::move(*reinterpret_cast(other.storage))); else new (storage) E(std::move(*reinterpret_cast(other.storage))); } Result& operator=(const Result&) = delete; bool isOk() const noexcept { return ok; } const T& value() const { return *reinterpret_cast(storage); } const E& error() const { return *reinterpret_cast(storage); } }; // Specialisation for Result template class Result { bool ok; alignas(E) unsigned char storage[sizeof(E)]; Result() = default; public: static Result success() { Result res; res.ok = true; return res; } static Result failure(E err) { Result res; res.ok = false; new (res.storage) E(std::move(err)); return res; } ~Result() { if (!ok) reinterpret_cast(storage)->~E(); } Result(const Result& other) : ok(other.ok) { if (!ok) new (storage) E(*reinterpret_cast(other.storage)); } Result(Result&& other) : ok(other.ok) { if (!ok) new (storage) E(std::move(*reinterpret_cast(other.storage))); } Result& operator=(const Result&) = delete; bool isOk() const noexcept { return ok; } const E& error() const { return *reinterpret_cast(storage); } }; } // namespace nxst