'Can I somehow filter any_view<A const&, forward | sized> view?
Even for A being int, a naive approach for filtering fails,
#include <range/v3/view/any_view.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
#include <vector>
using namespace ranges;
using namespace ranges::views;
constexpr auto noop = [](int const& i) -> int const& { return (i); };
using View = any_view<int const&, category::forward | category::sized>;
template<std::size_t n>
View fun(View v) {
if constexpr (n == 0)
return v | transform(noop); // transforming is fine, the view stays the same size
else
return v | filter(noop); // lazy filtering doesn't work, as the view is no more sized
}
int main() {
std::vector<int> va{1, 2, 3, 4, 5};
View w{va};
auto w2 = fun<0>(w); // succeeds
//auto w3 = fun<1>(w); // fails at compile-time
}
let alone A beging a user defined class.
From the comments you see I understand the reason for the failure: v | filter(noop)'s size can be known only upon traversing the whole v, which is done in linear, not constant time, so it does not meet the requirements of the sized_range concept, hence it can't be used to construct a any_view<int const&, forward | sized>.
transforming, on the other hand, is possible, as it doesn't alter the size of the range.
But still, from within fun, I know that if the enclosing program is well written, the View v parameter has cog int const& references to all valid ints living in main, so I don't see why I can't do an eager filtering and construct a any_view from that.
However, I'm not sure how I can do it (and if).
Here's how my idea starts and breaks:
- I filter, as that's the plan,
- then, I take the address of the items, so I get things that can be copied around without loosing track of the original objects I'm working with
- I convert to a hard vector to trigger the traversal of the
filterview, thus obtaining a range of known size, but which contains pointers to original data, not copied of the original data - finally... what do I do? I have a
std::vector<A const*>and I want to return aany_view<A const&, forward | sized>. How can I do it?indirectdoesn't seem to be the answer, as you can see below:
#include <boost/hof/lift.hpp>
#include <iostream>
#include <functional>
#include <memory>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/any_view.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/indirect.hpp>
#include <range/v3/view/transform.hpp>
#include <vector>
using namespace ranges;
using namespace ranges::views;
using A = int; // so I can easily change it to a user defined class later
constexpr auto noop = [](A const& i) -> decltype(auto) { return (i); };
constexpr auto addressof = BOOST_HOF_LIFT(std::addressof); // so I can pass it around
using View = any_view<A const&, category::forward | category::sized>;
View fun(View v) {
std::vector<A const*> w = v | filter(noop) | transform(addressof) | to_vector;
return w | ranges::views::indirect;
}
int main() {
std::vector<A> va(5);
View w{va};
auto w3 = fun(w); // succeeds
std::cout << w3 << std::endl; // segmentation fault, so I'm playing with garbage
}
(any_view is not in C++20, so I'm tagging range-v3c++17; but I suspect the problem will exist in C++ whenever such a view will be added, so I'm also adding std-ranges.)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
