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?
The recent proposal P2494R0 also addresses this issue and proposes a detailed resolution.
Range adaptor closure objects are objects whose type is the same as one of the following objects (ignoring cv-qualification): objects of user-defined types other than unary range adaptor objects who meet the requirements of implementing a range adaptor closure object, the results of binding trailing arguments by range adaptor objects, and
They are callable via the pipe operator: if C is a range adaptor closure object and R is a viewable_range (until C++23) range (since C++23), these two expressions are equivalent (both well-formed or ill-formed): This call forwards the bound arguments (if any) to the associated range adaptor object.
The ranges library provides components for dealing with ranges of elements, including a variety of view adapters. The namespace alias std::views is provided as a shorthand for std::ranges::views . Some range adaptors wrap their elements or function objects with the copyable wrapper .
This call forwards the bound arguments (if any) to the associated range adaptor object. The bound arguments (if any) are identically treated as lvalue or rvalue and cv-qualified to C .
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With