I have a third-party function with this signature:
std::vector f(T t);
I also have an existing potentially infinite range (of the
UPDATE
range-v3 now has views::cache1, a view that caches the most recent element in the view object itself, and returns a reference to that object. That is how this problem is cleanly and efficiently solved today, as pointed out by user @bradgonesurfing in his answer.
Old, out-of-date answer below, preserved for historical curiosity.
This is another solution that doesn't require much fancy hacking. It comes at the cost of a call to std::make_shared at each call to f. But you're allocating and populating a container in f anyway, so maybe this is an acceptable cost.
#include
#include
#include
#include
#include
#include
#include
std::vector f(int i) {
return std::vector(3u, i);
}
template
struct shared_view : ranges::view_interface> {
private:
std::shared_ptr ptr_;
public:
shared_view() = default;
explicit shared_view(Container &&c)
: ptr_(std::make_shared(std::move(c)))
{}
ranges::range_iterator_t begin() const {
return ranges::begin(*ptr_);
}
ranges::range_iterator_t end() const {
return ranges::end(*ptr_);
}
};
struct make_shared_view_fn {
template ())>
shared_view> operator()(Container &&c) const {
return shared_view>{std::forward(c)};
}
};
constexpr make_shared_view_fn make_shared_view{};
int main() {
using namespace ranges;
auto rng = view::ints | view::transform(compose(make_shared_view, f)) | view::join;
RANGES_FOR( int i, rng ) {
std::cout << i << '\n';
}
}