#include <exception>
#include <stdexcept>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
using error_type = std::exception_ptr;
struct ResultBase
{
bool hasError() const
{
return *reinterpret_cast<const bool*>(this);
}
std::exception_ptr error() const
{
return *reinterpret_cast<const error_type*>(
reinterpret_cast<const char*>(this)
+ sizeof(std::max_align_t));
}
protected:
ResultBase() { }
};
template <class T>
struct Result : ResultBase
{
Result(error_type error)
: mHasError(true) { new (&mError) error_type(error); }
Result(T value)
: mHasError(false) { new (&mValue) T(value); }
~Result()
{
if (mHasError)
mError.~error_type();
else
mValue.~T();
}
void setError(error_type error)
{
if (mHasError) {
mError = error;
} else {
mValue.~T();
new (&mError) error_type(error);
mHasError = true;
}
}
void setValue(T value)
{
if (mHasError) {
mError.~error_type();
new (&mValue) T(value);
mHasError = false;
} else {
mValue = value;
}
}
private:
union {
bool mHasError;
std::max_align_t mAligner;
};
union {
error_type mError;
T mValue;
};
};
static_assert(std::is_standard_layout<Result<int>>::value, "");
void check(bool condition)
{
if (!condition) std::terminate();
}
void f(const ResultBase& alias, Result<int>& r)
{
check(!alias.hasError());
r.setError(std::exception_ptr());
check(alias.hasError());
check(alias.error() == nullptr);
r.setValue(1);
check(!alias.hasError());
r.setError(std::make_exception_ptr(std::runtime_error("!")));
check(alias.hasError());
check(alias.error() != nullptr);
}
int main()
{
Result<int> r(0);
f(r, r);
}