The for-loop works fine because the vector<int>
(rvalue) is valid while the loop is evaluated.
The second code snippet has 2 issues:
- The predicate must return a
bool
- the
vector<int>
you are using in the views object is dangling by the time it is evaluated, so the compiler does not accept it.
If instead of a vector<int>
rvalue, the object cannot dangle (lvalue) or holds references into something else that cannot not dangle, this would work.
For example:
auto vec = std::vector<int>({0, 1});
auto vw = vec | std::ranges::views::filter([](int i) { std::cout << i; return true; });
Or you can pass an rvalue that has references to a non-dangling vector<int>
object, like std::span
:
auto vec = std::vector<int>({0, 1});
auto vw = span{vec} | std::ranges::views::filter([](int i) { std::cout << i; return true; })
Here, std::span
is still a rvalue, but the compiler accepts it because the author of std::span
has created an exception for it.
For a custom type with references into something else (typically views), you can create your own exception by creating a specialization of the template variable enable_borrowed_range
.
In the case of vector it would look like this (but don't do this!):
template<> // don't do this
inline constexpr bool ranges::enable_borrowed_range<std::vector<int>> = true;
Your code now compiles but it will trigger undefined behavior because the vector is dangling once the view is evaluated.