c++generatorc++20std-ranges

How to implement generator that can be used with ranges views


I'm using C++20, and I'm trying to implement a custom generator. I'm reusing an implementation of the Generator from here: https://en.cppreference.com/w/cpp/coroutine/coroutine_handle This example works well, but this generator doesn't work with std::ranges::views:

// This loop works:
for (const char i : range(65, 91))
    std::cout << i << ' ';

// This loop produces compiler error: no match for ‘operator|’ (operand types are ‘Generator’ and ‘std::ranges::views::__adaptor::_Partial’) 
for (const char i : range(65, 91) | std::views::take(3))
    std::cout << i << ' ';

So, as I understand the error message, I need to define the Generator<T>::operator| as a template method for all possible ranges::views. I'm looking for a reference implementation of this method. Or a more generic question: what shall I do to pipe the result of the generator to any view, like that: range(65, 91) | std::views::take(3)?

Update The cppreference link I'm providing above has an implementation of a Generator and provides the following example of usage:

template<std::integral T>
Generator<T> range(T first, const T last)
{
    while (first < last)
        co_yield first++;
}

In my real code I'm using another function that defines an algorithm that produces values (and not necessarily integers). My goal is to improve the Generator to make it possible to pipeline the output to a view.


Solution

  • Your Generator's Iter class does not satisfy the C++20 input_iterator concept, which requires member types of value_type/difference_type as well as a postfix++, which in turn makes the Generator not satisfy the range concept, so the range adaptor cannot be applied.

    Adding these missing pieces allows compilation

    class Iter
    {
        public:
            using value_type = T;
            using difference_type = std::ptrdiff_t;
            Iter& operator++()
            {
                m_coroutine.resume();
                return *this;
            }
            void operator++(int)
            {
                m_coroutine.resume();
            }
            // ...
    };
    

    Demo