Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SinglePassRangeConcept should support non-const range #133

Open
grtowel1510f opened this issue Mar 19, 2022 · 1 comment
Open

SinglePassRangeConcept should support non-const range #133

grtowel1510f opened this issue Mar 19, 2022 · 1 comment

Comments

@grtowel1510f
Copy link

grtowel1510f commented Mar 19, 2022

A single pass range often can be consumed only once which implies mutability and negates constness, on the first consumption it becomes empty. SinglePassRangeConcept asserts const_constraints which is a requirement that cannot be met by many or most single pass ranges.

I will demonstrate using a boost coroutine with a range adaptor:

#include <boost/range/adaptor/transformed.hpp>
#include <boost/coroutine2/coroutine.hpp>

using boost::adaptors::transformed;
using boost::coroutines2::coroutine;

int main() {
    using generator = coroutine<int>;
    generator::pull_type g([](auto &yield) {
        for (int i = 0; i < 10; i++) {
            yield(i);
        }
    });

    for (auto i: g | transformed([](int i) { return i + 10; })) {
    }

    return 0;
}

This code snippet does not compile because SinglePassRangeConcept asserts const_constraints which boost coroutine does not satisfy.

I propose to drop the const requirement for SinglePassRangeConcept because in simple terms, a single pass range isn't required to have a const iterator.

@grtowel1510f
Copy link
Author

grtowel1510f commented Mar 19, 2022

This is a reduction of the previous coroutine demonstration using a simplified generator class to realize a better controlled experiment:

#include <iterator>
#include <boost/range/adaptor/transformed.hpp>

class generator {
public:
    int i = 0;
    int& value() { return i; }
    void next() { i++; }
    bool empty() const { return i == 10; }

    class iterator {
    public:
        using iterator_category = std::input_iterator_tag;
        using iterator_concept = std::input_iterator_tag;
        using difference_type = ptrdiff_t;
        using value_type = int;
        using pointer = int*;
        using reference = int&;

        generator *g;

        reference operator*() const { return g->value(); }
        iterator& operator++() {
            g->next();
            return *this;
        }
        inline iterator& operator++(int) { return operator++(); }
        bool operator==(const iterator& other) const {
            if (other.g == nullptr) {
                return !g || g->empty();
            }
            return g == other.g;
        }

        bool operator!=(const iterator& other) const { return !operator==(other); }

        iterator(generator& g) : g(&g) {}
        iterator() = default;
    };

    iterator begin() {
        return iterator(*this);
    }

    iterator end() {
        return iterator();
    }

};

using boost::adaptors::transformed;

int main() {
    generator g;
    for (auto i : g | transformed([](int i) { return i + 10; })) {
    }

    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant