#ifndef EXPECTED_H #define EXPECTED_H #include template class Expected { union { T m_value; std::exception_ptr m_error; }; bool m_valid; Expected() {} // internal use public: Expected(const T& rhs) : m_value(rhs), m_valid(true) {} Expected(T&& rhs) : m_value(std::move(rhs)) , m_valid(true) {} Expected(const Expected& rhs) : m_valid(rhs.valid) { if (m_valid) { new (&m_value) T(rhs.m_value); } else { new (&m_error) std::exception_ptr(rhs.m_error); } } Expected(Expected &&rhs) : m_valid(rhs.m_valid) { if (m_valid) { new (&m_value) T(std::move(rhs.m_value)); } else { new (&m_error) std::exception_ptr(std::move(rhs.m_error)); } } ~Expected() { if (m_valid) { m_value.~T(); } else { using std::exception_ptr; m_error.~exception_ptr(); } } // void swap(Expected& rhs) // { // if (m_valid) { // if (rhs.m_valid) { // using std::swap; // swap(m_value, rhs.m_value); // } // else { // auto t = std::move(rhs.m_error); // new(&rhs.m_value) T(std::move(m_value)); // new(&m_error) std::exception_ptr(t); // std::swap(m_valid, rhs.m_valid); // } // } // else { // if (rhs.m_valid) { // rhs.swap(*this); // } // else { // using std::swap; // swap(m_error, rhs.m_error); // std::swap(m_valid, rhs.m_valid); // } // } // } template static Expected fromException(const E& exception) { if (typeid(exception) != typeid(E)) { throw std::invalid_argument("slicing detected"); } return fromException(std::make_exception_ptr(exception)); } static Expected fromException(std::exception_ptr p) { Expected result; result.m_valid = false; new (&result.m_error) std::exception_ptr(std::move(p)); return result; } static Expected fromException() { return fromException(std::current_exception()); } bool valid() const { return m_valid; } T& get() { if (!m_valid) { std::rethrow_exception(m_error); } return m_value; } const T& get() const { if (!m_valid) { std::rethrow_exception(m_error); } return m_value; } template bool hasException() const { try { if (!m_valid) { std::rethrow_exception(m_error); } } catch (const E& ) { return true; } catch (...) { } return false; } template static Expected fromCode(F fun) { try { return Expected(fun()); } catch (...) { return fromException(); } } }; template <> class Expected { std::exception_ptr m_error; bool m_valid; public: Expected() : m_valid(true) {} Expected(const Expected& rhs) : m_valid(rhs.m_valid) , m_error(rhs.m_error) {} Expected(Expected &&rhs) : m_valid(rhs.m_valid) , m_error(std::move(rhs.m_error)) {} ~Expected() {} // void swap(Expected& rhs) // { // if (m_valid) { // if (!rhs.m_valid) { // m_error = rhs.m_error; // std::swap(m_valid, rhs.m_valid); // } // } // else { // if (rhs.m_valid) { // rhs.swap(*this); // } // else { // using std::swap; // swap(m_error, rhs.m_error); // std::swap(m_valid, rhs.m_valid); // } // } // } template static Expected fromException(const E& exception) { if (typeid(exception) != typeid(E)) { throw std::invalid_argument("slicing detected"); } return fromException(std::make_exception_ptr(exception)); } static Expected fromException(std::exception_ptr p) { Expected result; result.m_valid = false; result.m_error = std::exception_ptr(std::move(p)); return result; } static Expected fromException() { return fromException(std::current_exception()); } bool valid() const { return m_valid; } void get() const { if (!m_valid) { std::rethrow_exception(m_error); } } template bool hasException() const { try { if (!m_valid) { std::rethrow_exception(m_error); } } catch (const E& ) { return true; } catch (...) { } return false; } template static Expected fromCode(F fun) { try { fun(); return Expected(); } catch (...) { return fromException(); } } }; #endif // EXPECTED_H