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
It is a bad idea to infer the lifetime property of the elements from a generic range's value category. For example:
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.ranges::transform_view<std::span<std::string>, some_function>
rvalue, even though it is not a borrowed_range
.boost::iterator_range<std::string*>
, even though this legacy type has not declared itself to be a view
;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.