Consider the following code snippet (full code: https://godbolt.org/z/PMM4z9KvM):
int main() {
{
std::cout << "begin std::views::as_rvalue\n";
auto iss = std::istringstream("12");
auto is = std::views::istream<X>(iss);
auto _ = is | std::views::as_rvalue | std::ranges::to<std::vector>();
std::cout << "end std::views::as_rvalue\n\n" << std::flush;
}
{
std::cout << "\nbegin my::as_rvalue\n";
auto iss = std::istringstream("12");
auto is = std::views::istream<X>(iss);
auto _ = is | my::as_rvalue | std::ranges::to<std::vector>();
std::cout << "end my::as_rvalue\n\n" << std::flush;
}
}
The output is as follows:
begin std::views::as_rvalue
X()
X(X const&)
X(X&&)
~X()
X(X&&)
X(X&&)
X(X&&)
~X()
~X()
end std::views::as_rvalue
~X()
~X()
~X()
begin my::as_rvalue
X()
X(X&&)
X(X&&)
X(X&&)
~X()
end my::as_rvalue
~X()
~X()
~X()
It seems std::views::as_rvalue
has more operations than my::as_rvalue
.
Why is std::views::as_rvalue
not so cheap as std::move_iterator
?
As with all standard range adaptors, std::views::as_rvalue<V>
stores a copy of the adapted view V
. It's constructor is effectively defined as:
constexpr explicit as_rvalue_view(V base) : base(std::move(base_)) {}
This accounts for the extra copy and move constructions, and destructions.