Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the C++23 ranges adaptor require a callable object to be copy_­constructible?

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?

Update:

The recent proposal P2494R0 also addresses this issue and proposes a detailed resolution.

like image 592
康桓瑋 Avatar asked Oct 09 '21 13:10

康桓瑋


People also ask

What is a range adaptor closure object?

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

How do you call a viewable_range from a range adaptor?

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.

What is the use of ranges in C++?

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 .

What are the bound arguments of a range adaptor?

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 .


1 Answers

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.

like image 144
T.C. Avatar answered Oct 19 '22 11:10

T.C.