4

I have access to GCC 10 and compile with -std=c++20, and need views such as generate cache1, concat etc that aren't slated until possibly C++23.

I wrote a simple program below that outputs '1 2 2 3 3 3' using range-v3. I tried to mix the range-v3 views and the views from the ranges include without success. The 'ranges' library seems to expect views to inherit from the view_interface, so I created a wrap_view_t to help with that (not shown). To see the working range-v3 code, comment the line:

//#define MIX_RANGES_WITH_RANGE_V3

Code follows:

#include <iostream>

#define MIX_RANGES_WITH_RANGE_V3

#ifdef  MIX_RANGES_WITH_RANGE_V3
#include <ranges>
namespace test { using namespace std::ranges; }
#else
#include <range/v3/view/all.hpp>
#include <range/v3/view/interface.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/view/take_while.hpp>
#include <range/v3/view/transform.hpp>
namespace test { using namespace ranges; }
#endif
#include <range/v3/view/generate.hpp>
#include <range/v3/view/cache1.hpp>


auto my_view()
{
  auto gen{ ranges::views::generate( [ n = 0 ]() mutable
  {
    return std::vector< int >( ++n, n );
  } )
    | ranges::views::cache1
  };

  return std::move( gen )
    | test::views::take_while( []( auto const & value ) { return value.size() < 4; } )
    | test::views::transform( []( auto const & value )
    { return test::views::all( value ); } );

}

int main()
{
  for( auto const value : my_view() | test::views::join )
  {
    std::cout <<value <<" ";
  }
  std::cout <<std::endl;

  return 0;
}

And the compiler error(s)

test_rng/test_rng_simpler.C: In function ‘auto my_view()’:
test_rng/test_rng_simpler.C:28:3: error: no match for ‘operator|’ (operand types are ‘std::remove_reference<ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >&>::type’ {aka ‘ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >’} and ‘std::ranges::views::__adaptor::_RangeAdaptorClosure<std::ranges::views::__adaptor::_RangeAdaptor<_Callable>::operator()<{my_view()::<lambda(const auto:16&)>}>::<lambda(_Range&&)> >’)
   27 |  return std::move( gen )
      |         ~~~~~~~~~~~~~~~~
      |                  |
      |                  std::remove_reference<ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >&>::type {aka ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >}
   28 |   | test::views::take_while( []( auto const & value ) { return value.size() < 4; } )
      |   ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                            |
      |                            std::ranges::views::__adaptor::_RangeAdaptorClosure<std::ranges::views::__adaptor::_RangeAdaptor<_Callable>::operator()<{my_view()::<lambda(const auto:16&)>}>::<lambda(_Range&&)> >
In file included from test_rng/test_rng_simpler.C:6:
/opt/rh/devtoolset-10/root/usr/include/c++/10/ranges:1180:4: note: candidate: ‘template<class _Tp> constexpr auto std::ranges::views::__adaptor::operator|(const std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>&, const std::ranges::views::__adaptor::_RangeAdaptorClosure<std::ranges::views::__adaptor::_RangeAdaptor<_Callable>::operator()<{my_view()::<lambda(const auto:16&)>}>::<lambda(_Range&&)> >&)’
 1180 |    operator|(const _RangeAdaptorClosure<_Tp>& __x,
      |    ^~~~~~~~
/opt/rh/devtoolset-10/root/usr/include/c++/10/ranges:1180:4: note:   template argument deduction/substitution failed:
test_rng/test_rng_simpler.C:28:84: note:   ‘std::remove_reference<ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >&>::type’ {aka ‘ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >’} is not derived from ‘const std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>’
   28 |   | test::views::take_while( []( auto const & value ) { return value.size() < 4; } )
      |                                                                                    ^
In file included from test_rng/test_rng_simpler.C:6:
/opt/rh/devtoolset-10/root/usr/include/c++/10/ranges:1175:4: note: candidate: ‘constexpr auto std::ranges::views::__adaptor::operator|(_Range&&, const std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>&) [with _Range = ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >; _Callable = std::ranges::views::__adaptor::_RangeAdaptor<_Callable>::operator()<{my_view()::<lambda(const auto:16&)>}>::<lambda(_Range&&)>]’
 1175 |    operator|(_Range&& __r, const _RangeAdaptorClosure& __o)
      |    ^~~~~~~~
/opt/rh/devtoolset-10/root/usr/include/c++/10/ranges:1175:4: note: constraints not satisfied
test_rng/test_rng_simpler.C: In instantiation of ‘constexpr auto std::ranges::views::__adaptor::operator|(_Range&&, const std::ranges::views::__adaptor::_RangeAdaptorClosure<_Callable>&) [with _Range = ranges::cache1_view<ranges::generate_view<my_view()::<lambda()> > >; _Callable = std::ranges::views::__adaptor::_RangeAdaptor<_Callable>::operator()<{my_view()::<lambda(const auto:16&)>}>::<lambda(_Range&&)>]’:
test_rng/test_rng_simpler.C:28:84:   required from here
/opt/rh/devtoolset-10/root/usr/include/c++/10/ranges:78:13:   required for the satisfaction of ‘viewable_range<_Range>’ [with _Range = ranges::cache1_view<ranges::generate_view<my_view::._anon_131> >]
/opt/rh/devtoolset-10/root/usr/include/c++/10/ranges:79:31: note: no operand of the disjunction is satisfied
   79 |       && (borrowed_range<_Tp> || view<remove_cvref_t<_Tp>>);
      |          ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Perhaps I should stick with 'range-v3' until all of the views I need are available in the 'ranges' include?

cigien
  • 57,834
  • 11
  • 73
  • 112
  • *"To see the compile errors, uncomment the line:"* I would default to problematic code. – Jarod42 Oct 04 '21 at 19:36
  • I can simplify and remove the wrap_view_t to show the issue I mentioned where "ranges" seems to expect views to derive from view_interface – PantsPlusPlus Oct 04 '21 at 19:46
  • If you need ranges-v3, maybe use it for everything and abandon standard ranges? This should give you more portability too, e.g. Clang still has problems with standard ones. – HolyBlackCat Oct 04 '21 at 20:47
  • Thanks @HolyBlackCat, I will likely stick with range-v3 for the c++20 timeframe, unless someone comments with a clever solution that helps with interoperability with the c++20 standard. – PantsPlusPlus Oct 04 '21 at 20:51

1 Answers1

3

Since the adapters in range-v3 do not inherit ranges::view_interface, this makes them not a view in the standard. In order to avoid the danger of dangling, the standard prohibits passing a range that does not model the borrowed_range or view (gen in your example) into the pipe.

What you need to do is to use a temporary variable to accept generate to make it an lvalue range, so that the borrowed_range can be satisfied and the standard pipe operation can be used:

#include <iostream>
#include <ranges>
#include <range/v3/view/generate.hpp>
#include <range/v3/view/cache1.hpp>

int main() {
  auto gen = ranges::views::generate([n = 0]() mutable {
      return std::vector<int>(++n, n);
    }) | ranges::views::cache1;

  for (auto const value : gen
    | std::views::take_while([](auto const& value) { return value.size() < 4; })
    | std::views::transform([](auto const& value) { return std::views::all(value); })
    | std::views::join) {
      std::cout <<value <<" ";
  }
}

Demo.

康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • Thanks, but if you change the GCC version up until 10.3 in the "Demo" this does not compile: https://godbolt.org/z/6xzfn33nj :14:19: required from here /opt/compiler-explorer/gcc-10.3.0/include/c++/10.3.0/ranges:2495:12: error: no type named 'iterator_category' in 'struct std::iterator_traits > > >, main():: >, main():: >::_Iterator >' 2495 | using _OuterCat – PantsPlusPlus Oct 05 '21 at 07:04
  • 1
    @user17073881 It is not a bug, it is just because gcc-10 has not completed the [P2259](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2259r1.html). If you use gcc-11, it can be compiled. In addition, since gcc-11.2 has implemented [P2328](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2328r1.html), you can [omit the step of transforming the inner range into view](https://godbolt.org/z/e5rsvaf51). – 康桓瑋 Oct 05 '21 at 07:08
  • Is there a solution for GCC 10.X? Or is interoperability between the standard 'ranges' and 'range-v3' available first starting with GCC 11.X? – PantsPlusPlus Oct 05 '21 at 07:11
  • Strictly speaking, before [P2328](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2328r1.html), the standard did not have a safe way to perform such pipe operations, because what the `generator` returns is a `range` of pr value. If you cannot upgrade your compiler, then I suggest you just use range-v3. – 康桓瑋 Oct 05 '21 at 07:20
  • 1
    Thank you for all the help @康桓瑋. I'm looking forward to GCC 11.X and will stick with range-v3 while using GCC 10.X – PantsPlusPlus Oct 05 '21 at 07:24