I understand people like implicit constructors until they find that they don't want them here or there.
void f(optional<T>); T x; f(x);
Later on add void f(expected<T>); T x; f(x); // ambiguous :(
This is fine. It's a compile time error. Writing f(expected<T>(x)) eliminates the ambiguity.
So T is a subset of two sets and then we need to be explicit. Been explicit from the beginning avoids surprises.
This is just a compile-time surprise, so this is not all that bad. But you may get a run-time surprise
vector<T> x; void f(expected
); f(x); // are you aware that you are copying a vecotor?
If people fail to use std::move, they should always assume a copy. Except when returning from a function. f(std::move(x)) would do the right thing here I believe.
Maybe no-one uses expected<T> as function parameter, but consider this:
expected
g() { vector<T> v; // try to populate v; return v; // are you expecting a copy elision here? }
This is definitely a concern for C++ 14 (not 17). But I think end users get this problem with implicit conversion - it helps that recent clangs have a rich set of warnings when you do an inefficient return of a stack allocated object. So I don't think it as much a problem as others think.
Even if we wanted that expected
is valid only if T is different from E, I believe the explicitness has added value.
Throughout AFIO v2, I not only **always** return via make_valued_result
or make_errored_result, I found myself specifying the return type too
e.g. make_valued_result