康桓瑋*_*康桓瑋 10 c++ c++20 std-ranges c++23
一些范围适配器,例如filter_\xc2\xadview,take_\xc2\xadwhile_\xc2\xadview和transform_view使用std::optional\ 的同类copyable-box来存储可调用对象:
template<input_\xc2\xadrange V, copy_\xc2\xadconstructible F>\nclass transform_view : public view_interface<transform_view<V, F>> {\n private:\n V base_ = V();\n copyable-box<F> fun_;\n};\nRun Code Online (Sandbox Code Playgroud)\n这要求可调用对象F为copy_\xc2\xadconstructible,这也阻止我们将捕获仅移动对象的可调用对象传递给transform_view(Godbolt):
#include <ranges>\n#include <memory>\n\nstruct MoveOnlyFun {\n std::unique_ptr<int> x;\n MoveOnlyFun(int x) : x(std::make_unique<int>(x)) { } \n int operator()(int y) const { return *x + y; }\n};\n\nint main() {\n auto r = std::views::iota(0, 5)\n | std::views::transform(MoveOnlyFun(1));\n}\nRun Code Online (Sandbox Code Playgroud)\n既然view不是必需的copy_constructible,为什么我们要求可调用的呢copy_constructible?为什么我们不直接使用moveable-box来存储可调用的而不是copyable-box?这背后有哪些考虑?
最近的提案P2494R0也解决了这个问题,并提出了详细的解决方案。
\n所有算法都需要可复制构造的函数对象,而视图基本上是惰性算法。
从历史上看,当添加这些适配器时,视图必须是copyable,因此我们要求函数对象是copy_constructible(我们不能copyable在不排除捕获式 lambda 的情况下要求)。view后来才进行了仅需要的更改movable。
放宽限制可能是可能的,但需要一份文件,而且并不是真正的优先事项。