Home > Software engineering >  ranges views size does not compile
ranges views size does not compile

Time:02-13

#include <iostream>
#include <cstdlib>
#include <vector>
#include <ranges>
#include <algorithm>
using namespace std;


int main()
{
    vector<int> ints = {1,2,3,4,5};
    auto v = ints | views::take_while([](int i){return i<3;}) ;
    for (int i : v) std::cout << i << ' ';
    std::cout << '\n';
    int size = v.size();
    std::cout << size << std::endl;
}

v.size() does not compile. How do you do this ?

prog.cc: In function 'int main()':
prog.cc:16:23: error: no matching function for call to 'std::ranges::take_while_view<std::ranges::ref_view<std::vector<int> >, main()::<lambda(int)> >::size()'
   16 |     int size = v.size();
      |                       ^
In file included from prog.cc:5:
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ranges:144:7: note: candidate: 'constexpr auto std::ranges::view_interface<_Derived>::size() requires (forward_range<_Derived>) && (sized_sentinel_for<decltype(std::ranges::__cust::end((declval<_Tp&>)())), decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>) [with _Derived = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int> >, main()::<lambda(int)> >]'
  144 |       size()
      |       ^~~~
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ranges:144:7: note: constraints not satisfied
In file included from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/stl_iterator_base_types.h:71,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/stl_algobase.h:65,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/char_traits.h:39,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ios:40,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ostream:38,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/iostream:39,
                 from prog.cc:2:
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h: In instantiation of 'constexpr auto std::ranges::view_interface<_Derived>::size() requires (forward_range<_Derived>) && (sized_sentinel_for<decltype(std::ranges::__cust::end((declval<_Tp&>)())), decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>) [with _Derived = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int> >, main()::<lambda(int)> >]':
prog.cc:16:23:   required from here
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:555:13:   required for the satisfaction of 'sized_sentinel_for<std::ranges::sentinel_t<_Tp>, decltype (std::__detail::__ranges_begin(declval<_Container&>()))>' [with _Tp = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int, std::allocator<int> > >, main::._anon_124>; _Container = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int, std::allocator<int> > >, main::._anon_124>]
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:557:8:   in requirements with 'const _Iter& __i', 'const _Sent& __s' [with _Arg = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >; _Sent = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int, std::allocator<int> > >, main::._anon_124>::_Sentinel<true>; _Iter = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >]
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:559:13: note: the required expression '(__s - __i)' is invalid
  559 |       { __s - __i } -> same_as<iter_difference_t<_Iter>>;
      |         ~~~~^~~~~
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:560:13: note: the required expression '(__i - __s)' is invalid
  560 |       { __i - __s } -> same_as<iter_difference_t<_Iter>>;
      |         ~~~~^~~~~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
In file included from prog.cc:5:
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ranges:150:7: note: candidate: 'constexpr auto std::ranges::view_interface<_Derived>::size() const requires (forward_range<const _Derived>) && (sized_sentinel_for<decltype(std::ranges::__cust::end((declval<const _Range&>)())), decltype(std::__detail::__ranges_begin((declval<const _Range&>)()))>) [with _Derived = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int> >, main()::<lambda(int)> >]'
  150 |       size() const
      |       ^~~~
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ranges:150:7: note: constraints not satisfied
In file included from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/stl_iterator_base_types.h:71,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/stl_algobase.h:65,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/char_traits.h:39,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ios:40,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/ostream:38,
                 from /opt/wandbox/gcc-10.2.0/include/c  /10.2.0/iostream:39,
                 from prog.cc:2:
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h: In instantiation of 'constexpr auto std::ranges::view_interface<_Derived>::size() const requires (forward_range<const _Derived>) && (sized_sentinel_for<decltype(std::ranges::__cust::end((declval<const _Range&>)())), decltype(std::__detail::__ranges_begin((declval<const _Range&>)()))>) [with _Derived = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int> >, main()::<lambda(int)> >]':
prog.cc:16:23:   required from here
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:555:13:   required for the satisfaction of 'sized_sentinel_for<std::ranges::sentinel_t<const _Range>, decltype (std::__detail::__ranges_begin(declval<const _Range&>()))>' [with _Range = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int, std::allocator<int> > >, main::._anon_124>]
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:557:8:   in requirements with 'const _Iter& __i', 'const _Sent& __s' [with _Arg = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >; _Sent = std::ranges::take_while_view<std::ranges::ref_view<std::vector<int, std::allocator<int> > >, main::._anon_124>::_Sentinel<true>; _Iter = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >]
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:559:13: note: the required expression '(__s - __i)' is invalid
  559 |       { __s - __i } -> same_as<iter_difference_t<_Iter>>;
      |         ~~~~^~~~~
/opt/wandbox/gcc-10.2.0/include/c  /10.2.0/bits/iterator_concepts.h:560:13: note: the required expression '(__i - __s)' is invalid
  560 |       { __i - __s } -> same_as<iter_difference_t<_Iter>>;
      |         ~~~~^~~~~

CodePudding user response:

Since take_while and its ilk shorten the size of the list in unpredictable ways, those range adaptors cannot return a sized_range, even if the input itself is sized. sized_range requires that the range can compute the size in O(1) time, and take_while's view cannot do that.

So if you want the size (and you shouldn't), you will have to compute it yourself. You could also use std::ranges::distance on the range.

  • Related