#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);
}
