I need to copy projections of some elements from one range to another in case they meet the predicate.
- The
std::ranges::copy_if
uses projection only to pass the result to
the predicate, projection result can’t be copied; only the original
data. - The necessary transformation could be done with the
std::ranges::transform
, but it copies all elements, since there is
nostd::ranges::transform_if
.
Is there a way to copy the projections without allocating intermediate containers and making excessive intermediate copies?
Thus:
std::ranges::transform(src,temp,op);
std::ranges::copy_if (temp,dest,pred);
works, but requires temp
container and excessive copy.
Of course, this can easily be implemented with std::ranges::for_each
, but I am curious if there is more straightforward solution in ranges?
And of course I can write something like:
template <class InputIt, class OutputIt, class Pred, class Proj>
void transform_if(InputIt first, InputIt last, OutputIt dest, Pred pred, Proj projection)
{
while (first != last) {
if (pred(*first)) {
*dest++ = projection(*first);
}
++first;
}
}
but I don’t want to reinvent the wheel if there is more simple and straightforward solution in ranges.
The ranges library includes both range algorithms, which are applied to ranges eagerly, and range adaptors, which are applied to views lazily. Adaptors can be composed into pipelines, so that their actions take place as the view is iterated.
auto result = src | std::views::filter(pred) | std::views::transform(op);
std::ranges::copy(result, dst);
result
is lazily evaluated thus this won’t create any unnecessary copies.
I don’t think so. Note that boost contains this function, but it’s just as well to use your version if you’re not already pulling in such a heavy dependency.
just use
std::view::filter
in place ofstd::ranges::copy_if
. Which version of C++ standard do you use? 20/23?@MarekR, I use the latest version of C++ (with all experimental features). My case is that
src
is the array of indexes and projection gets elements by this indexes from another container. I am not surestd::view::filter
will do here, since I don’t have an idea how it would convert dispersed array data in one range. If this could be done, I could prepare demo so that you could pinpoint thestd::view::filter
usage (in case this can’t be easily answered in the original terms of the question).Please provide some example so it is clear what is a goal. Is this ok: godbolt.org/z/xrThhj5vo ?
@MarekR, thank you so much! This is exactly what I was looking for! With one reservation, I wanted to copy it in the resulting vector with
std::back_inserter
like here, but this last step was easy when you have showed the key part.