为什么 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 和参数类型。 const
、noexcept
和 ref-qualifiers 都在起作用,这引入了新的设计问题。例如,从 int (*)(int)
推导出 int(int)
吗?为什么不是 int(int) const
- 毕竟函数指针是 const-callable?
如果事实证明需要 CTAD - 并且有人为它提出了一个好的设计 - 它总是可以在以后添加。
我不知道这些观点是否都在 LEWG 讨论中提出(会议记录相当稀疏),但我认为它们足以证明不支持 CTAD。
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 和参数类型。 const
、noexcept
和 ref-qualifiers 都在起作用,这引入了新的设计问题。例如,从 int (*)(int)
推导出 int(int)
吗?为什么不是 int(int) const
- 毕竟函数指针是 const-callable?
如果事实证明需要 CTAD - 并且有人为它提出了一个好的设计 - 它总是可以在以后添加。
我不知道这些观点是否都在 LEWG 讨论中提出(会议记录相当稀疏),但我认为它们足以证明不支持 CTAD。