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_function
overstd::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::function
deprecated bystd::copyable_function
in 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.