Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using zip_view piped into a filter_view

I am getting compilation erorr while trying to zip two vectors and apply and filter as below.

#include <range/v3/all.hpp>

int main()
{
    std::vector v1 = {0, 1, 2, 3, 4};
    std::vector v2 = {'a', 'b', 'c', 'd', 'e'};

    auto pred = [](auto& p) { return (p.first != 0); };

    auto x = ranges::views::zip(v1, v2);
    auto y = x | ranges::views::filter(pred);
}

Here is compilation error

<source>: In function 'int main()':
<source>:15:16: error: no match for 'operator|' (operand types are 'ranges::zip_view<ranges::ref_view<std::vector<int, std::allocator<int> > >, ranges::ref_view<std::vector<char, std::allocator<char> > > >' and 'ranges::views::view_closure<ranges::detail::bind_back_fn_<ranges::views::filter_base_fn, main()::<lambda(auto:28&)> > >')
   15 |     auto y = x | ranges::views::filter(pred);
      |              ~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |              |                        |
      |              |                        ranges::views::view_closure<ranges::detail::bind_back_fn_<ranges::views::filter_base_fn, main()::<lambda(auto:28&)> > >
      |              ranges::zip_view<ranges::ref_view<std::vector<int, std::allocator<int> > >, ranges::ref_view<std::vector<char, std::allocator<char> > > >
In file included from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/regex:40,
                 from /opt/compiler-explorer/libs/rangesv3/0.12.0/include/range/v3/view/tokenize.hpp:18,
                 from /opt/compiler-explorer/libs/rangesv3/0.12.0/include/range/v3/view.hpp:81,
                 from /opt/compiler-explorer/libs/rangesv3/0.12.0/include/range/v3/all.hpp:25,
                 from <source>:4:
like image 613
Shakti Malik Avatar asked Sep 04 '26 00:09

Shakti Malik


2 Answers

You'll need a const& in your pred:

auto pred = [](auto const& p) { return p.first != 0; };

This can also be achieved by using a forwarding reference:

auto pred = [](auto&& p) { return p.first != 0; };

Demo

like image 123
Ted Lyngmo Avatar answered Sep 05 '26 14:09

Ted Lyngmo


The elements of a zip_view (as returned from views::zip) are objects of type std::pair<T&, U&> where the two elements of the pair refer into the original sequences. That is, the overloaded operator zip_view::iterator::operator*() const has std::tuple<T&, U&> as its return type. So the result of *it is a prvalue, not an lvalue.

Meanwhile, your predicate is trying to take auto& — i.e. "give me an lvalue reference to something." But the library doesn't want to give it an lvalue. The library wants to give it a prvalue pair. So you need to change that auto& to something that is willing to bind to an rvalue: as Ted said, either const auto& or auto&&.

In this case, it could arguably be better to just take auto by value, since pair<T&, U&> is small, cheap-to-copy, and trivial-for-purposes-of-calls. You don't really need a reference to it. But the counterargument is that taking it by value shows "unwarranted chumminess with the implementation"; if you want to avoid making any assumptions about the return type of iterator::operator*, I'd say auto&& is best.

like image 25
Quuxplusone Avatar answered Sep 05 '26 15:09

Quuxplusone



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!