According to cppreference, std::views::split
call signature (https://en.cppreference.com/w/cpp/ranges/split_view ):
template< ranges::viewable_range R, class Pattern >
requires /* see below */
constexpr ranges::view auto split( R&& r, Pattern&& pattern );
Those pattern
is passed by reference.
But then why doesn't it compile:
std::vector a{ 1,2,-1,-2,3,4,-1,-2,5,6,7,-1,-2,8 };
std::vector delimiter{ -1, -2 };
auto sv = a | std::views::split(delimiter);
auto jv = sv | std::views::join; //Error
And for the above code fragment to work, you have to manually wrap pattern
using ref_view:
std::vector a{ 1,2,-1,-2,3,4,-1,-2,5,6,7,-1,-2,8 };
std::vector delimiter{ -1, -2 };
auto sv = a |
std::views::split(std::ranges::ref_view(delimiter));
auto jv = sv | std::views::join; //Ok
It seems that std::views::split doesn't use a reference to pattern
, but creates a copy of pattern
. What exactly is happening here?
The reason is that a | std::views::split(delimiter)
is not the same as
std::views::split(a, delimiter)
. Going via a RangeAdaptorObject means you need to store a copy of delimiter
, which you then use as a rvalue. The deduction guide for std::ranges::split_view
uses std::ranges::all_t
, which chooses std::views::owning_view
for rvalues, instead of std::views::ref_view
, which it chooses for lvalues.
when the call is valid, its result object stores a subobject of type
std::decay_t<E>
direct-non-list-initialized withstd::forward<E>(e)
, for every argumente
inargs...
(in other words, range adaptor objects bind arguments by value),calling the RangeAdaptorClosureObject forwards the bound arguments (if any) to the associated range adaptor object. The bound arguments (if any) are considered to have the value category and cv-qualification of the RangeAdaptorClosureObject.
It also compiles in the following situations, either because the adaptor is an lvalue, or we move from the owning_view
1.
auto sv = std::views::split(delimiter);
auto split = a | sv;
auto jv = split | std::views::join; // OK
auto sv = std::views::split(delimiter);
auto jv = a | sv | std::views::join; // OK
auto sv = a | std::views::split(delimiter);
auto jv = std::move(sv) | std::views::join; // OK
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