C++23 introduced std::function
's cousin std::move_only_function
, just like its name, it is a move-only wrapper for move-only callable objects (demo):
#include <functional>
#include <memory>
int main() {
auto l = [p = std::make_unique<int>(0)] { };
std::function<void(void)> f1{std::move(l)}; // ill-formed
std::move_only_function<void(void)> f2{std::move(l)}; // well-formed
}
But unlike std::function
, the standard does not define deduction guides for it (demo):
#include <functional>
int func(double) { return 0; }
int main() {
std::function f1{func}; // guide deduces function<int(double)>
std::move_only_function f2{func}; // deduction failed
}
Is there a reason for banning CTAD?
Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
It lets you store function pointers, lambdas, or classes with operator() . It will do conversion of compatible types (so std::function<double(double)> will take int(int) callable things) but that is secondary to its primary purpose.
No. One is a function pointer; the other is an object that serves as a wrapper around a function pointer. They pretty much represent the same thing, but std::function is far more powerful, allowing you to do make bindings and whatnot.
Yes, unless you catch it, or unless you mark the destructor noexcept(false) . And in the latter case you have to be pretty careful or it may result in std::terminate() anyway.
The standard C++ library gained a function template called std::move, which, despite its name, does not move anything. std::move merely casts its argument to an rvalue reference to allow moving it, but doesn't guarantee a move operation. For example, we can write a more effective version of swap using std::move :
It included multiple references to implementations of move-only functions and made a strong case for the importance of a move-only form of std::function . Feebdack given was encouragement for targetting C++20. An updated version of that paper was presented on Saturday at the end of the San Diego meeting.
If a std::move_only_function contains no target, it is called empty. Unlike std::function, invoking an empty std::move_only_function results in undefined behavior. std::move_only_functions supports every possible combination of cv-qualifiers, ref-qualifiers, and noexcept-specifiers not including volatile provided in its template parameter.
However, std::move must be used judiciously; using it blithely may lead to performance degradation, or simply be redundant, affecting readability of the code. Fortunately, the compiler can sometimes help with finding such wrong uses of std::move.
Type-erasing wrappers like move_only_function
are designed to be used on API boundaries, where the types are explicit, which makes CTAD for these of dubious usefulness.
Any CTAD for these callable wrappers would have to be quite limited anyway - it can't handle overloaded functions or function templates, which also means that it can't handle generic lambdas, which is a rather significant limitation on its usefulness. std::function
's CTAD also comes with a disclaimer that later standards can change the deduced type (we haven't changed it yet, but we haven't removed the disclaimer either).
And with move_only_function
it's not just the return and argument types that are deduced. const
, noexcept
, and ref-qualifiers are all in play, and that introduces new design issues. For instance, does deducing from int (*)(int)
deduce int(int)
? Why not int(int) const
- function pointers are const-callable, after all?
And if CTAD turns out to be needed - and someone come up with a good design for it - it can always be added later.
I don't know if these points were all raised in the LEWG discussion (the minutes are rather sparse), but I think they are more than enough to justify not supporting CTAD.
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