Created
December 8, 2019 14:18
-
-
Save hqhs/c5532f773e957f8717c4c06030f4f3c8 to your computer and use it in GitHub Desktop.
Updated "expected" version from Andrei Alexandrescu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <class T, class E> class expected | |
{ | |
union { | |
T yay; | |
E nay; | |
}; | |
bool ok = true; | |
public: | |
expected() { new (&yay) T(); } | |
expected(const T &rhs) { new (&yay) T(rhs); } | |
expected(const unexpected<E> &rhs) : ok(false) { new (&nay) E(rhs.value()); } | |
template <class U = T> explicit expected(U &&rhs) | |
{ | |
new (&yay) T(forward<U>(rhs)); | |
} | |
expected(const expected &rhs) : ok(rhs.ok) | |
{ | |
if (ok) | |
new (&yay) T(rhs.yay); | |
else | |
new (&nay) E(rhs.nay); | |
} | |
expected(expected &&rhs) : ok(rhs.ok) | |
{ | |
if (ok) | |
new (&yay) T(std::move(rhs.yay)); | |
else | |
new (&nay) E(std::move(rhs.nay)); | |
} | |
T &operator*() | |
{ | |
// if (!ok) throw nay; | |
return yay; // UB galore | |
} | |
const T &operator*() const; | |
T &&operator*() &&; | |
const T &&operator*() const &&; | |
T *operator->() { return &**this; } | |
const T *operator->() const; | |
const E &error() const | |
{ | |
assert(!ok); | |
return nay; | |
} | |
E &error(); | |
E &&error() &&; | |
const E &&error() const &&; | |
bool has_value() const noexcept { return ok; } | |
explicit operator bool() const noexcept { return ok; } | |
T &expected::value() & | |
{ | |
if (!ok) | |
throw nay; | |
return yay; | |
} | |
const T &expected::value() const &; | |
T &&expected::value() &&; | |
const T &&expected::value() const &&; // any useful scenario? | |
// Returns value() of ok, T(forward<U>(v)) otherwise | |
template <class U> T value_or(U &&v) const &; | |
template <class U> T value_or(U &&v) &&; | |
enable_if_t<is_nothrow_move_constructible_v<T> && is_swappable_v<T &> && | |
is_nothrow_move_constructible_v<E> && is_swappable_v<E &>> | |
swap(expected &rhs) | |
{ | |
if (ok) | |
{ | |
if (rhs.ok) | |
{ | |
using std::swap; | |
swap(yay, rhs.yay); | |
} | |
else | |
{ | |
rhs.swap(*this); | |
} | |
} | |
else | |
{ | |
if (!rhs.ok) | |
{ | |
using std::swap; | |
swap(nay, rhs.nay); | |
} | |
else | |
{ | |
E t{std::move(nay)}; | |
nay.~E(); | |
new (&yay) T(std::move(rhs.yay)); | |
ok = true; | |
rhs.yay.~T(); | |
new (&rhs.nay) E(std::move(t)); | |
rhs.ok = false; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Original talk