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

Weird SizedRange compilation problem #237

Open
adah1972 opened this issue Dec 15, 2018 · 2 comments
Open

Weird SizedRange compilation problem #237

adah1972 opened this issue Dec 15, 2018 · 2 comments

Comments

@adah1972
Copy link

The following code shows a compilation problem:

#include <experimental/ranges/concepts>
#include <experimental/ranges/ranges>
#include <iostream>
#include <iterator>
#include <string>

/** Class to allow iteration over all lines from an input stream. */
class istream_line_reader {
public:
    /**
     * Iterator that contains the line content.
     *
     * The iterator \e owns the content.
     */
    class iterator  // implements InputIterator
    {
    public:
        typedef int                     difference_type;
        typedef std::string             value_type;
        typedef value_type*             pointer_type;
        typedef value_type&             reference;
        typedef std::input_iterator_tag iterator_category;

        iterator() : _M_stream(nullptr) {}
        explicit iterator(std::istream& is) : _M_stream(&is)
        {
            ++*this;
        }

        reference operator*()
        {
            assert(_M_stream != nullptr);
            return _M_line;
        }
        pointer_type operator->()
        {
            assert(_M_stream != nullptr);
            return &_M_line;
        }
        iterator& operator++()
        {
            assert(_M_stream != nullptr);
            getline(*_M_stream, _M_line);
            if (!*_M_stream)
                _M_stream = nullptr;
            return *this;
        }
        iterator operator++(int)
        {
            iterator temp(*this);
            ++*this;
            return temp;
        }

        bool operator==(const iterator& rhs) const
        {
            return _M_stream == rhs._M_stream;
        }
        bool operator!=(const iterator& rhs) const
        {
            return !operator==(rhs);
        }

    private:
        std::istream* _M_stream;
        std::string   _M_line;
    };

    istream_line_reader() noexcept
        : _M_stream(nullptr)
    {
    }
    explicit istream_line_reader(std::istream& is) noexcept
        : _M_stream(&is)
    {
    }
    iterator begin()
    {
        return iterator(*_M_stream);
    }
    iterator end() const
    {
        return iterator();
    }

private:
    std::istream* _M_stream;
};

#define TEST_CONCEPT(Concept, Type...) \
    cout << #Concept << '<' << #Type << ">: " << Concept<Type> << endl

int main()
{
    namespace ranges = std::experimental::ranges;
    using ranges::Range;
    using ranges::View;
    using ranges::SizedRange;
    using std::cout;
    using std::endl;
    cout << std::boolalpha;
    auto line_reader = istream_line_reader(std::cin);
    auto rng = line_reader | ranges::view::take(5);
    TEST_CONCEPT(Range, decltype(line_reader));
    TEST_CONCEPT(View, decltype(line_reader));
    TEST_CONCEPT(SizedRange, decltype(line_reader));
    TEST_CONCEPT(Range, decltype(rng));
    TEST_CONCEPT(View, decltype(rng));
    TEST_CONCEPT(SizedRange, decltype(rng));  // DOESN'T COMPILE
    for (auto& line : rng) {
        cout << line << endl;
    }
}

I intend to check which concepts are satisfied. However, the line TEST_CONCEPT(SizedRange, decltype(rng)); (marked above) does not compile. I expect to see it compile and output false at run time.

Which one is at fault, my code, CMCSTL2, or GCC? I doubt it is GCC this time, but I would like to hear experts’ opinions.

@adah1972
Copy link
Author

The problem is gone after I add const to the definition of pointer_type, reference, operator*, and operator->() of istream_line_reader::iterator (thanks to Eric’s help):

        typedef const value_type*       pointer_type;
        typedef const value_type&       reference;
…
        reference operator*() const
        {
            assert(_M_stream != nullptr);
            return _M_line;
        }
        pointer_type operator->() const
        {
            assert(_M_stream != nullptr);
            return &_M_line;
        }

It still feels strange why checking concept could cause compilation errors. . . .

@ericniebler
Copy link
Collaborator

You are right; it shouldn't be a hard error. I had overlooked that part of your bug report. I or @CaseyCarter will investigate.

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

2 participants