range-v3 forbids views over temporary containers to help us avoid the creation of dangling iterators. Your example demonstrates exactly why this rule is necessary in view compositions:
auto rng = src | view::transform(f) | view::join;
If view::join
were to store the begin
and end
iterators of the temporary vector returned by f
, they would be invalidated before ever being used.
"That's all great, Casey, but why don't range-v3 views store temporary ranges like this internally?"
Because performance. Much like how the performance of the STL algorithms is predicated on the requirement that iterator operations are O(1), the performance of view compositions is predicated on the requirement that view operations are O(1). If views were to store temporary ranges in internal containers "behind your back" then the complexity of view operations - and hence compositions - would become unpredictable.
"Ok, fine. Given that I understand all of this wonderful design, how do I MAKE THIS WORK?!??"
Since the view composition won't store the temporary ranges for you, you need to dump them into some kind of storage yourself, e.g.:
#include <iostream>
#include <vector>
#include <range/v3/range_for.hpp>
#include <range/v3/utility/functional.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/view/transform.hpp>
using T = int;
std::vector<T> f(T t) { return std::vector<T>(2, t); }
int main() {
std::vector<T> buffer;
auto store = [&buffer](std::vector<T> data) -> std::vector<T>& {
return buffer = std::move(data);
};
auto rng = ranges::view::ints
| ranges::view::transform(ranges::compose(store, f))
| ranges::view::join;
unsigned count = 0;
RANGES_FOR(auto&& i, rng) {
if (count) std::cout << ' ';
else std::cout << '\n';
count = (count + 1) % 8;
std::cout << i << ',';
}
}
Note that the correctness of this approach depends on the fact that view::join
is an input range and therefore single-pass.
"This isn't novice-friendly. Heck, it isn't expert-friendly. Why isn't there some kind of support for 'temporary storage materialization™' in range-v3?"
Because we haven't gotten around to it - patches welcome ;)