Some ranges adaptors such as filter_view
, take_while_view
and transform_view
use std::optional
's cousin copyable-box
to store the callable object:
template<input_range V, copy_constructible F>
class transform_view : public view_interface<transform_view<V, F>> {
private:
V base_ = V();
copyable-box<F> fun_;
};
which requires the callable F
to be copy_constructible
, this also prevents us from passing in the callable that captures the move only object into transform_view
(Godbolt):
#include <ranges>
#include <memory>
struct MoveOnlyFun {
std::unique_ptr<int> x;
MoveOnlyFun(int x) : x(std::make_unique<int>(x)) { }
int operator()(int y) const { return *x y; }
};
int main() {
auto r = std::views::iota(0, 5)
| std::views::transform(MoveOnlyFun(1));
}
Since the view
is not required to be copy_constructible
, why do we require the callable to be copy_constructible
? why don't we just use moveable-box
to store callable instead of copyable-box
? What are the considerations behind this?
CodePudding user response:
All the algorithms require copy-constructible function objects, and views are basically lazy algorithms.
Historically, when these adaptors were added, views were required to be copyable
, so we required the function objects to be copy_constructible
(we couldn't require copyable
without ruling out captureful lambdas). The change to make view
only require movable
came later.
It is probably possible to relax the restriction, but it will need a paper and isn't really high priority.