C++26 provides std::copyable_function [cppref link]. However, the existing std::function is already copyable. So, I have 3 questions:
What are the key advantages of std::copyable_function over std::function?
Invoking an empty std::copyable_function is undefined, while invoking an empty std::function will throw an exception. What's the rationale behind?
Is std::function deprecated by std::copyable_function in C++26?
What are the key advantages of
std::copyable_functionoverstd::function?
There are two.
First, there's no target() API, which generally wasn't super useful anyway, so there's less overhead because std::copyable_function doesn't have to track something that std::function did. But that's minor.
The more important one is the API surface. std::function looks like this:
struct function<R(Args...)> {
R operator()(Args...) const;
};
The call operator (1) always const and (2) never noexcept. (1) is a problem because you can still invoke a non-const member function without you intending to.
std::copyable_function looks like this:
struct copyable_function<R(Args...) cv ref noexc> {
R operator()(Args...) cv ref noexc;
};
Meaning that, for instance, copyable_function<void(int)> has a non-const, non-noexcept call operator, but copyable_function<void(int) const noexcept> has one that is both const and noexcept. All of this is specifiable.
This makes the usage clear and descriptive... and more correct!
Invoking an empty std::copyable_function is undefined, while invoking an empty std::function will throw an exception. What's the rationale behind?
Arguably, invoking an empty std::function is a bug. There are many people who think that throwing to signal programmer error is a bad way to do so - calling it undefined behavior means the implementation can assert.
Is
std::functiondeprecated bystd::copyable_functionin C++26?
The literal answer to this question is: no. But maybe the more interesting question is: should it have been? To which I would still answer no.
There's a very large amount of code that uses std::function and a large percentage of it is likely correct. It's also not a simple renaming to transition either, since many uses will want to change from function<R(Args...)> to copyable_function<R(Args...) const>. But also many uses will want to change to move_only_function<R(Args...) const> instead.
It's probably a good idea to actually make those changes (especially if you don't need target(), which ... nobody does). But they're not so pressing that you actually want a [[deprecated]] warning out of it. Seems more like a low-key clang-tidy modernization hint kind of suggestion.
There's really two levels here:
A is bad (possibly actively harmful), B is strictly superior, please switch.A is fine, B is better. Prefer B in new code, but A isn't harmful.Transitioning from auto_ptr<T> to unique_ptr<T> fits into that first category. Transitioning from function<R(Args..)> to copyable_function<R(Args...) const> (or move_only_function<R(Args...) const>, or sometimes even function_ref<R(Args...) const>) to me is more like the second category. A is fine. Don't yell at me for still using it in older code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With