Niall Douglas wrote:
There has been a fair bit of review feedback that people don't like the formal empty state in outcome<T> and result<T>. I still think this opinion daft, just because it's there doesn't mean you have to use it, but here are some options:
1. Like Expected, we could require the E types to provide a nothrow move constructor. This would allow us to guarantee no empty state, not ever. Default constructing an outcome<T> or result<T> would set a default constructed T state, just like Expected.
As I said, my preference is to indeed require E to provide nothrow move - which shouldn't be hard as E is in our case std::error_code which already does - and then to either: 1a. make result<T>/outcome<T> default-construct to T{} or 1b. make them default-construct to `make_error_code( outcome::errc::uninitialized_result )`. The inability of 1b to be constexpr is a bit annoying, but (a) that's arguably a defect in the standard, not on our side, and (b) if one wants a constexpr result<T>, one could always initialize it explicitly to T{}. For result<void>/outcome<void> I tend towards 1a, that is, always default-construct to a value result, even when result<T> is 1b. That's inconsistent, but there's parallel with ordinary functions where if you leave void f() without a return, all is well, but leaving int f() without a return is undefined.