We're not talking about U -> optional<Z> -> optional<T> though, we're talking about U -> optional<T> directly. Intuitively it seems that that should be preferred over U -> T -> optional<T>.
Another case that I think is ultimately related:
#include <functional>
int main() {
std::copyable_function<void()> f;
std::move_only_function<void()> g = f;
if (g)
g(); // oops, throws std::bad_function_call (and crashes)
}
If I'm writing my own type-erased function wrappers, I can check in my constructor (replacing move_only_function) whether the source object is a disengaged function wrapper. But I can't fix the constructor of move_only_function if replacing copyable_function, even if I know exactly how I want to convert to move_only_function.
namespace my {
concept FunctionWrapper = ...;
struct MoveOnlyFunction {
MoveOnlyFunction(FunctionWrapper auto); // called
};
struct CopyableFunction {
operator FunctionWrapper auto() const; // not called
};
}