cmcstl2
cmcstl2 copied to clipboard
Weird SizedRange compilation problem
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.
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. . . .
You are right; it shouldn't be a hard error. I had overlooked that part of your bug report. I or @CaseyCarter will investigate.