为什么 C++23 std::move_only_function 没有演绎指南?

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

C++23 引入了 std::function 的堂兄 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
}

但不像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
}

是否有禁止 CTAD 的原因?

Type-erasing 像 move_only_function 这样的包装器被设计用于 API 边界,其中类型是明确的,这使得 CTAD 对这些具有可疑的用途。

无论如何,这些可调用包装器的任何 CTAD 都必须非常有限——它不能处理重载函数或函数模板,这也意味着它不能处理通用 lambda,这是它的一个相当重要的限制用处。 std::function 的 CTAD 还附带了一个免责声明,以后的标准可以更改推导类型(我们还没有更改它,但我们也没有删除免责声明)。

而对于 move_only_function,推导的不仅仅是 return 和参数类型。 constnoexceptref-qualifiers 都在起作用,这引入了新的设计问题。例如,从 int (*)(int) 推导出 int(int) 吗?为什么不是 int(int) const - 毕竟函数指针是 const-callable?

如果事实证明需要 CTAD - 并且有人为它提出了一个好的设计 - 它总是可以在以后添加。

我不知道这些观点是否都在 LEWG 讨论中提出(会议记录相当稀疏),但我认为它们足以证明不支持 CTAD。