I have this code that fails (Explorer):
#include <range/v3/view/any_view.hpp>
#include <vector>
int main() {
std::vector<int> a{1};
const ranges::any_view<int, ranges::category::forward> av(a);
ranges::begin(av);
}
And was in the impression that begin
returns a new iterator into the range, that allows me to iterate through it several times. Why would it need a modifiable range for that?
As reference (but I'm more interested in the reason of the above than (just) a solution to my problem below), in my real code, this appears as
void merge(ranges::any_view<int, ranges::category::forward> av) {
for(auto x : av) { ... }
}
And unfortunately clang-tidy
warns that av
should be made const&
because it's passed by value but not moved inside of the function body.
My suspicion is that it has to do with the "amortized constant time complexity" requirement of begin
/ end
calls. The following fails because I think the begin
iterator can't be cached in the const
view returned by drop
:
std::list<int> b{1, 2, 3, 4};
const auto latter = ranges::views::all(b) | ranges::views::drop(2);
ranges::begin(latter);
So just in case the type-erased variable contains such a view, it has to cache the first result of begin
for all wrapped types. However, even if I change av
to random_access
, it won't let me call begin
on a const any_view
:
const ranges::any_view<int, ranges::category::random_access> av(a);
And if this is indeed the reason why it fails for input
, I wonder whether there's a way around this? Like the std::move_only_function
allows a moving std::function
(kind of) in C++23.