Date: Fri, 8 Dec 2023 11:00:06 -0500
On Thu, Dec 7, 2023 at 10:29 AM Edward Catmur via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> 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.
However #2: the copyable_function => move_only_function conversion problem
seems closely related to the function_ref => function conversion problem:
https://quuxplusone.github.io/blog/2019/05/10/function-ref-vs-string-view/#but-consider
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`.
–Arthur
std-proposals_at_[hidden]> wrote:
> 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.
However #2: the copyable_function => move_only_function conversion problem
seems closely related to the function_ref => function conversion problem:
https://quuxplusone.github.io/blog/2019/05/10/function-ref-vs-string-view/#but-consider
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`.
–Arthur
Received on 2023-12-08 16:00:19