Why does C++23 std::move_only_function not have deduction guides?
Asked Answered
H

1

14

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?

Hammers answered 9/10, 2021 at 17:52 Comment(2)
There's no need to suspect, the vote on CTAD is there open-std.org/jtc1/sc22/wg21/docs/papers/2021/… - 1 in favor vs 9 against.Tanto
you could ask the the authors authors of the paper, e.g. on twitter @ CppSage and @ sempuki1 or the email addresses in the paperAccumbent
S
13

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.

Sardinia answered 21/10, 2021 at 2:18 Comment(2)
If there is a free function void foo(), I think move_only_function can be deduced to void() just as std::function does since it is obviously intuitive. And we can still assign it to a callable that has void operator() or void operator() const. When the callable has both const and non-const qualified operator(), calling the latter also seems to be a more intuitive choice because we deduce the type through a free function. If we want to call operator() const, we must specify void() const explicitly at the beginning.Saccharin
The point is that the answers are not exactly obvious (on the flip side, does []{} deduce void() const?). Normally the way to design this would be to look at actual use cases - except that for move_only_function CTAD, there are not many use cases to start with.Sardinia

© 2022 - 2024 — McMap. All rights reserved.