c++c++20perfect-forwardingstd-ranges

Is there a move-or-copy equivalent of std::forward for perfect forwarding in std::ranges?


How can I combine the following two functions into one? Is there something similar to std::forward, but for ranges?

#include <ranges>
#include <vector>
#include <algorithm>

template<class RangeIn, class RangeOut>
void moveOrCopy(RangeIn& from, RangeOut& to)
{
    std::ranges::copy(from, std::back_inserter(to));
}

template<class RangeIn, class RangeOut>
    requires std::is_rvalue_reference_v<RangeIn&&>
void moveOrCopy(RangeIn&& from, RangeOut& to)
{
    std::ranges::move(from, std::back_inserter(to));
}

void test()
{
  std::vector<int> a, b;
  moveOrCopy(a, b); // copy
  moveOrCopy(std::move(a), b); // move
}

There is std::ranges::forward_range, but that's related to forward_iterator, not perfect forwarding.


Handy tool with the above code: https://cppinsights.io/s/45c86608

Intuitive reference for C++ references: https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers


Solution

  • It is a bad idea to infer the lifetime property of the elements from a generic range's value category. For example:

    1. A std::span<std::string> should not have its elements moved from, even if the span is an rvalue; the value category of the span is completely irrelevant.
    2. Likewise for a ranges::transform_view<std::span<std::string>, some_function> rvalue, even though it is not a borrowed_range.
    3. Likewise for a boost::iterator_range<std::string*>, even though this legacy type has not declared itself to be a view;
    4. Likewise for an owning_view<boost::iterator_range<std::string*>>, even though it's a specialization of owning_view.

    There's currently no concept or trait that would allow one to reliably detect when it's safe to do this. The best that can be done is to have the caller explicitly opt-in using something like views::as_rvalue in C++23.