首页 > 解决方案 > 为什么 C++23 std::move_only_function 没有推导指南?

问题描述

C++23 引入了std::function的表亲std::move_only_function,就像它的名字一样,它是一个只移动可调用对象(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的是,该标准没有为其定义演绎指南(演示):

#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 的理由吗?

标签: c++c++17std-functionc++23

解决方案


类型擦除包装器之类move_only_function的设计用于在 API 边界上使用,其中类型是显式的,这使得 CTAD 对这些有用的可疑之处。

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

并且move_only_function不仅仅是推导出的返回和参数类型。const, noexcept, 和ref-qualifiers都在起作用,这引入了新的设计问题。例如,是否从 deduc 进行int (*)(int)演绎int(int)?为什么不int(int) const——毕竟函数指针是可调用的?

如果 CTAD 被证明是必要的——并且有人为它想出了一个好的设计——它总是可以在以后添加。

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


推荐阅读