diff --git a/expected.hpp b/expected.hpp
new file mode 100644
index 0000000..72b3895
--- /dev/null
+++ b/expected.hpp
@@ -0,0 +1,431 @@
+///
+// expected - An implementation of std::expected with extensions
+// Written in 2017 by Simon Brand (@TartanLlama)
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this software to the
+// public domain worldwide. This software is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication
+// along with this software. If not, see
+// .
+///
+
+#ifndef TL_EXPECTED_HPP
+#define TL_EXPECTED_HPP
+
+#include
+
+namespace tl {
+ template
+ class unexpected {
+ public:
+ static_assert(!std::is_same, "E must not be void");
+ unexpected() = delete;
+ constexpr explicit unexpected(const E& e)
+ : m_val(e) {}
+
+ constexpr explicit unexpected(E&&)
+ : m_val(std::move(e)) {}
+
+ constexpr const E& value() const & { return m_val; }
+ constexpr E& value() & { return m_val; }
+ constexpr E&& value() && { return std::move(m_val); }
+ constexpr E const&& value() const&& { return std::move(m_val); }
+ private:
+ E m_val; // exposition only
+ };
+
+ template
+ constexpr bool
+ operator==(const unexpected& lhs, const unexpected& rhs) {
+ return lhs.value() == rhs.value();
+ }
+ template
+ constexpr bool
+ operator!=(const unexpected& lhs, const unexpected& rhs) {
+ return lhs.value() != rhs.value();
+ }
+}
+
+namespace detail {
+ template ::value, bool = std::is_trivially_destrictible::value>
+ struct expected_storage_base {
+ ~expected_storage_base() {
+ if (m_has_val) {
+ m_val.~T();
+ }
+ else {
+ m_unexpect.~unexpected();
+ }
+ }
+ bool m_has_val;
+ union {
+ T m_val;
+ unexpected m_unexpect;
+ };
+ };
+
+ template
+ struct expected_storage_base {
+ ~expected_storage_base() = default;
+ bool m_has_val;
+ union {
+ T m_val;
+ unexpected m_unexpect;
+ };
+ };
+
+ template
+ struct expected_storage_base {
+ ~expected_storage_base() {
+ if (!m_has_val) {
+ m_unexpect.~unexpected();
+ }
+ }
+
+ bool m_has_val;
+ union {
+ T m_val;
+ unexpected m_unexpect;
+ };
+
+ };
+
+ template
+ struct expected_storage_base {
+ ~expected_storage_base() {
+ if (m_has_val) {
+ m_val.~T();
+ }
+ }
+ bool m_has_val;
+ union {
+ T m_val;
+ unexpected m_unexpect;
+ };
+ };
+
+ template
+ struct expected_storage_base {
+ ~expected_storage_base() = default;
+
+ bool m_has_val;
+ struct dummy{};
+ union {
+ dummy m_val;
+ unexpected m_unexpect;
+ };
+ };
+
+ template
+ struct expected_storage_base {
+ ~expected_storage_base() {
+ if (m_has_val) {
+ m_val.~T();
+ }
+ }
+
+ bool m_has_val;
+ struct dummy{};
+ union {
+ dummy m_val;
+ unexpected m_unexpect;
+ };
+ };
+
+ //TODO, conditionally delete things
+ template
+ class expected_ctor_base{};
+}
+
+template
+class expected : private expected_storage_base, private expected_ctor_base {
+ static_assert(!std::is_reference::value, "T must not be a reference");
+ static_assert(!std::is_same>::value, "T must not be in_place_t");
+ static_assert(!std::is_same>::value, "T must not be unexpect_t");
+ static_assert(!std::is_same>::value, "T must not be unexpected");
+ static_assert(!std::is_reference::value, "E must not be a reference");
+ static_assert(!std::is_same::value, "T must not be void");
+
+public:
+ typedef T value_type;
+ typedef E error_type;
+ typedef unexpected unexpected_type;
+ template
+ struct rebind {
+ using type = expected;
+ };
+ // X.Z.4.1, constructors
+ constexpr expected_storage_base() :
+ m_val(T{}), m_has_val(true) {}
+
+ template ::value>* = nullptr>
+ constexpr expected_storage_base(in_place_t, Args&&... args) :
+ m_val(std::forward(args)...), m_has_val(true) {}
+
+ template &, Args&&...>::value>
+ constexpr expected_storage_base(in_place_t, std::initializer_list il, Args&&... args) :
+ m_val(il, std::forward(args)...), m_has_val(true) {}
+
+ template ::value>* = nullptr, detail::enable_if_t::value>* = nullptr>
+ explicit constexpr expected(unexpected const& e)
+ : m_unexpect(std::move(e)), m_has_value(false) {}
+
+ template ::value>* = nullptr, detail::enable_if_t::value>* = nullptr>
+ constexpr expected(unexpected const& e)
+ : m_unexpect(std::move(e)), m_has_value(false) {}
+
+ template ::value>* = nullptr, detail::enable_if_t::value>* = nullptr>
+ explicit constexpr expected(unexpected && e) noexcept(std::is_nothrow_constructible::value)
+ : m_unexpect(std::move(e)), m_has_value(false) {}
+
+ template ::value>* = nullptr, detail::enable_if_t::value>* = nullptr>
+ constexpr expected(unexpected && e) noexcept(std::is_nothrow_constructible::value)
+ : m_unexpect(std::move(e)), m_has_value(false) {}
+
+ template ::value>* = nullptr>
+ constexpr explicit expected(unexpect_t, Args&&... args) :
+ m_unexpect(std::forward(args)...), m_has_val(false) {}
+
+ template &, Args&&...>::value>* = nullptr>
+ constexpr explicit expected(unexpect_t, std::initializer_list il, Args&&... args) :
+ m_unexpect(il, std::forward(args)...), m_has_val(false) {}
+
+ constexpr expected(const expected& rhs) {
+ if (rhs.has_value()) {
+ new (std::addressof(m_value)) (*rhs);
+ }
+ else {
+ new (std::addressof(m_unexpect)) (unexpected(rhs.error()));
+ }
+ }
+
+ //TODO SFINAE
+ constexpr expected(expected&&) noexcept(std::is_nothrow_move_constructible_v && std::is_nothrow_move_constructible_v) {
+ if (rhs.has_value()) {
+ new (std::addressof(m_value)) (std::move(*rhs));
+ }
+ else {
+ new (std::addressof(m_unexpect)) (unexpected(std::move(rhs.error())));
+ }
+ }
+
+ //TODO SFINAE
+ template || !std::is_convertible::value>* = nullptr>
+ explicit constexpr expected(const expected& rhs) {
+ if (rhs.has_value()) {
+ new (std::addressof(m_value)) (*rhs);
+ }
+ else {
+ new (std::addressof(m_unexpect)) (unexpected(rhs.error()));
+ }
+ }
+
+ //TODO SFINAE
+ template || !std::is_convertible::value>* = nullptr>
+ explicit constexpr expected(const expected& rhs) {
+ if (rhs.has_value()) {
+ new (std::addressof(m_value)) (*rhs);
+ }
+ else {
+ new (std::addressof(m_unexpect)) (unexpected(rhs.error()));
+ }
+ }
+
+ //TODO SFINAE
+ template || std::is_convertible::value>* = nullptr>
+ constexpr expected(expected&&) {
+ if (rhs.has_value()) {
+ new (std::addressof(m_value)) (std::move(*rhs));
+ }
+ else {
+ new (std::addressof(m_unexpect)) (unexpected(std::move(rhs.error())));
+ }
+ }
+
+ //TODO SFINAE
+ template ::value>* = nullptr>
+ explicit constexpr expected(U&& v)
+ : expected_storage_base(in_place, std::forward(v))
+ {}
+
+ //TODO SFINAE
+ template ::value>* = nullptr>
+ constexpr expected(U&& v)
+ : expected_storage_base(in_place, std::forward(v))
+ {}
+
+//TODO
+ expected& operator=(const expected&);
+ expected& operator=(expected&&) noexcept(see below);
+ template expected& operator=(U&&);
+ template
+ expected& operator=(const unexpected&);
+ template
+ expected& operator=(unexpected&&) noexcept(see below);
+ template
+ void emplace(Args&&...);
+ template
+ void emplace(initializer_list, Args&&...);
+
+//TODO SFINAE
+ void swap(expected& rhs) noexcept(std::is_nothrow_move_constructible::value && noexcept(swap(declval(), declval())) && std::is_nothrow_move_constructible::value && noexcept(swap(declval(), declval())))
+ {
+ if (has_value() && rhs.has_value()) {
+ using std::swap;
+ swap(m_val, rhs.m_val);
+ }
+ else if (!has_value() && rhs.has_value()) {
+ using std::swap;
+ swap(m_unexpect, rhs.m_unexpect);
+ }
+ else if (has_value()) {
+ auto temp = std::move(rhs.m_unexpect);
+ new (std::addressof(rhs.m_val)) (m_val);
+ new (std::addressof(m_unexpect)) (temp);
+ std::swap(m_has_value, rhs.m_has_value);
+ }
+ else {
+ auto temp = std::move(m_unexpect);
+ new (std::addressof(m_val)) (rhs.m_val);
+ new (std::addressof(rhs.m_unexpect)) (temp);
+ std::swap(m_has_value, rhs.m_has_value);
+ }
+ }
+
+ constexpr const T* operator ->() const { return std::addressof(m_val); }
+ constexpr T* operator ->() { return std::addressof(m_val); }
+ constexpr const T& operator *() const& { return m_val; }
+ constexpr T& operator *() & { return m_val; }
+ constexpr const T&& operator *() const && { return std::move(m_val); }
+ constexpr T&& operator *() && { return std::move(m_val); }
+ constexpr explicit operator bool() const noexcept { return m_has_val; }
+ constexpr bool has_value() const noexcept { return m_has_val; }
+ constexpr const T& value() const& {
+ if (!m_has_value) throw bad_expected_access();
+ return m_value;
+ }
+ constexpr T& value() & {
+ if (!m_has_value) throw bad_expected_access();
+ return m_value;
+ }
+ constexpr const T&& value() const && {
+ if (!m_has_value) throw bad_expected_access();
+ return std::move(m_value);
+ }
+ constexpr T&& value() && {
+ if (!m_has_value) throw bad_expected_access();
+ return std::move(m_value);
+ }
+ constexpr const E& error() const& { return m_unexpect.value(); }
+ constexpr E& error() & { return m_unexpect.value(); }
+ constexpr const E&& error() const && { return std:move(m_unexpect.value()); }
+ constexpr E&& error() && { return std:move(m_unexpect.value()); }
+ template
+ constexpr T value_or(U&& v) const& {
+ static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy-constructible and convertible to from U&&");
+ return bool(*this) ? **this : static_cast(std::forward(v));
+ }
+ template
+ T value_or(U&&) && {
+ static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move-constructible and convertible to from U&&");
+ return bool(*this) ? std::move(**this) : static_cast(std::forward(v));
+
+ }
+};
+
+
+//TODO
+template
+class expected {
+
+};
+
+struct unexpect_t {
+ unexpect_t() = default;
+};
+ inline constexpr unexpect_t unexpect{};
+
+template
+class bad_expected_access : public bad_expected_access {
+public:
+ explicit bad_expected_access(E e)
+ : m_val(std::move(e)) {}
+
+ virtual const char* what() const noexcept override {
+ return "Bad expected access";
+ }
+
+ const E& error() const& { return m_val; }
+ E& error() & { return m_val; }
+ const E&& error() const && { return std::move(m_val); }
+ E&& error() && { return std::move(m_val); }
+private:
+ E m_val;
+};
+
+template <>
+class bad_expected_access : public exception {
+public:
+ explicit bad_expected_access();
+};
+
+ template <>
+ class bad_expected_access;
+
+ template
+ constexpr bool operator==(const expected& lhs, const expected& rhs) {
+ return (lhs.has_value() != rhs.has_value()) ? false :
+ (!lhs.has_value() ? lhs.error() == rhs.error()
+ : *lhs == *rhs);
+ }
+template
+constexpr bool operator!=(const expected& lhs, const expected& rhs) {
+ return (lhs.has_value() != rhs.has_value()) ? true :
+ (!lhs.has_value() ? lhs.error() != rhs.error()
+ : *lhs != *rhs);
+}
+
+ template
+ constexpr bool operator==(const expected& x, const T& v) {
+ return x.has_value() ? *x == v : false;
+ }
+ template
+ constexpr bool operator==(const T& v, const expected& x) {
+ return x.has_value() ? *x == v : false;
+ }
+ template
+ constexpr bool operator!=(const expected& x, const T& v) {
+ return x.has_value() ? *x != v : true;
+ }
+ template
+ constexpr bool operator!=(const T& v, const expected& x) {
+ return x.has_value() ? *x != v : true;
+ }
+
+ template
+ constexpr bool operator==(const expected& x, const unexpected& e) {
+ return x.has_value() ? true : x.error() == e.value();
+ }
+ template
+ constexpr bool operator==(const unexpected& e, const expected& x) {
+ return x.has_value() ? true : x.error() == e.value();
+ }
+ template
+ constexpr bool operator!=(const expected& x, const unexpected& e) {
+ return x.has_value() ? false : x.error() != e.value();
+ }
+ template
+ constexpr bool operator!=(const unexpected& e, const expected& x) {
+ return x.has_value() ? false : x.error() != e.value();
+ }
+
+
+//TODO is_swappable
+template ::value && std::is_move_constructible::value>* = nullptr>
+void swap(expected& lhs, expected& rhs) noexcept(noexcept(lhs.swap(rhs))) {
+ lhs.swap(rhs);
+}
+
+#endif