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)
}
I agree that this is unfortunate — and probably should be fixed — because that's the entire point of putting these types into the STL: so that they can interoperate correctly!
However #1: this really just shows that `function` should never have been nullable in the first place. The original sin here is using "g is truthy" as a proxy for "g is safe to call." The best approach is just to maintain a program invariant that you never branch on the truthiness of a `function` — if you're in a situation where you want a "maybe-a-function," you should just use `optional<function>` or some such. The bool conversion for `function` itself is a trap.
We have an empty state because `function` is semiregular, which is necessary since it is default-constructible and movable - given that a default-constructed state or a moved-from state exist, we may as well have both exist and be the same state. And then given that that state inhabits the type, we must have a way to distinguish that state and wide-contract methods that behave in a well-defined manner on encountering it.
However #2: the copyable_function => move_only_function conversion problem seems closely related to the function_ref => function conversion problem:
std::function<int()> convert(std::function_ref<int()> f) { return f; }
int main() {
std::function<int()> f = convert([]() { return 42; });
f(); // boom, this `function` stores a `function_ref` which is now dangling
}
In the function_ref case there's really nothing we can say other than "don't do that, then." It's the same as storing any other callable-containing-a-dangling-reference (e.g. most lambdas) into a `std::function`.
I feel that one direction is sensible (conversions in the direction copyable -> move_only -> ref should always be allowed), whereas the other direction is not, so conversions should be discouraged if allowed at all. Obviously a copyable_function cannot be constructed from a move_only_function at all, but similarly I feel that constructing a copyable_function or move_only_function from a function_ref should at least be explicit, precisely because it is prone to dangling.