Closed dbs4261 closed 5 years ago
You want to make your own view, like
std::vector<MyStruct<int, std::string>> in; // can be any RandomAccessRange
std::vector<std::size_t> indices; // can be any ForwardRange
auto out = in | my_transform(min, max, indides); // ForwardRange of ForwardRange of std::pair<int, std::string>
?
Or just ask how to pass indices
(Range) to operator()
instead of unsigned int ref_idx
? If so:
template<class Range> // Range of std::size_t
auto operator()(Range&& ref_ids) {
return ref_ids | view::transform([&data, min_val, max_val](std::size_t ref_idx){
// your code goes here...
const MyStruct<T, S>& ref_data = data.at(ref_idx);
auto distances = data | ranges::view::transform([&ref_data](const MyStruct<T, S>& cor_data)->T{
// Arbitrary function
return ref_data.a * 2 + cor_data.a * 3;
});
return ranges::view::zip(distances, ranges::view::iota(0)) |
ranges::view::remove_if([ref_idx](const auto& tup){return std::get<1>(tup) == ref_idx;}) |
ranges::view::remove_if([min_val=min_val, max_val=max_val](const auto& tup) {
return std::get<0>(tup) >= min_val and std::get<0>(tup) <= max_val;
}) |
ranges::view::transform([](const auto& tup){return std::get<1>(tup);});
});
});
}
Usage:
std::vector<MyStruct<int, std::string>> in; // can be any RandomAccessRange
std::vector<std::size_t> indices; // can be any ForwardRange
auto out = MyFunctor(in, 0, 10)(indides); // ForwardRange of ForwardRange of std::pair<int, std::string>
I feel that you don't need functor at all...:
template<class Data, class Indices>
auto my_converter(Data& data, Indices& indices, std::size_t min_val, std::size_t max_val){
return indices | view::transform([&data, min_val, max_val](std::size_t id){
// all as before...
});
};
Actually with something like this https://github.com/ericniebler/range-v3/pull/1177#issuecomment-491492488 , you could make:
auto my_view = view::range_adaptor([](auto&& data, auto&& indices, std::size_t min_val, std::size_t max_val){
return indices | view::transform([data = view::all(data), min_val, max_val](std::size_t id){
// all as before...
});
});
auto out = in | my_view(indices, 0, 10);
Sorry if I wasn't clear. Im looking for the correct way to pass a range to a function. In your examples you are showing input | view::transform([captured](auto&& parameter){return ...;});
If I extract that lambda to a functor, then the parameter is essentially the dereference type of whatever is piped in, and captured is passed to the constructor. When I'm writing that constructor, or any function for that matter, that takes a range as a parameter, how should I pass that range?
In my example I have: MyFunctor(const std::vector<MyStruct<T, S>>& _data, T _min_val, T _max_val) noexcept : data(_data), min_val(_min_val), max_val(_max_val) {}
If I want to use a range for _data instead of a vector, how would I pass it? Do I want to copy it, do I want to perfect forward? More than that, what is the type I should use? Do I need to use a template parameter for it and constrain it with a concept? If so how do I use the concept to enforce a certain dereference type?
Capture range by value (copy or move). Use template/auto, instead of direct type (you may want to constrain it to Range, if you know how to do that).
That's how internally range-v3 capture range:
template<class Range /* + Range constrains */> // Range must be a Range, not Container!
class MyFunctor{
public:
MyFunctor(Range range) : range(std::move(range)) {}
/// ....
private:
Range range;
};
std::vector<int> list;
MyFunctor fn{view:all(list)};
In order to be able to just to do MyFunctor fn{list}
, MyFunctor must have CTAD (https://en.cppreference.com/w/cpp/language/class_template_argument_deduction) rules:
template<typename Rng>
MyFunctor(Rng &&)->MyFunctor<view::all_t<Rng>>;
P.S. https://ericniebler.github.io/range-v3/ see "Adapting Ranges" section.
About constrains... They appeared only in C++20 https://en.cppreference.com/w/cpp/language/constraints
All other - emulation. range-v3
has that, but honestly, I would not recommend to use it as part of your project, since their interface can change... (it just changed a few month ago). At least yet...
In any case, compiler support for constraints is almost here... Just another half or one year to wait.
Thanks this was exactly what I was looking for. With respect to constraints and concepts, does the version that range-v3 uses attempt to follow what will be standardized?
With respect to constraints and concepts, does the version that range-v3 uses attempt to follow what will be standardized?
As far as I know, it tries... It tries to follow cpp20 constrain syntax, and it seems, that concepts used internally are same as cpp20's (there's just more of them).
And everything in namespace ranges::cpp20
should be drop in replacement for https://en.cppreference.com/w/cpp/ranges
I've been experimenting with updating some existing code to test out ranges. I've partially updated a section similar to the following. For every input index, a transform outputs a vector of indices based on the functor. However, I feel like I haven't completed my work updating this. Ideally, an input view of indices would result in an output view of views of indices. I think the auto return type will allow that creation of the view of views, however I am not sure how to pass the view to the functor.
So how do I pass a view to the constructor of this functor?