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?
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.