Issue 659: istreambuf_iterator should have an operator->() (original) (raw)


This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.

659. istreambuf_iterator should have an operator->()

Section: 24.6.4 [istreambuf.iterator] Status: C++11 Submitter: Niels Dekker Opened: 2007-03-25 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [istreambuf.iterator].

View all other issues in [istreambuf.iterator].

View all issues with C++11 status.

Discussion:

Greg Herlihy has clearly demonstrated that a user defined input iterator should have an operator->(), even if its value type is a built-in type (comp.std.c++, "Re: Should any iterator have an operator->() in C++0x?", March 2007). And as Howard Hinnant remarked in the same thread that the input iteratoristreambuf_iterator doesn't have one, this must be a defect!

Based on Greg's example, the following code demonstrates the issue:

#include #include #include

typedef char C; int main () { std::ifstream s("filename", std::ios::in); std::istreambuf_iterator i(s);

(*i).C(); // This is well-formed... i->C(); // ... so this should be supported! }

Of course, operator-> is also needed when the value_type ofistreambuf_iterator is a class.

The operator-> could be implemented in various ways. For instance, by storing the current value inside the iterator, and returning its address. Or by returning a proxy, like operator_arrow_proxy, fromhttp://www.boost.org/boost/iterator/iterator_facade.hpp

I hope that the resolution of this issue will contribute to getting a clear and consistent definition of iterator concepts.

[ Kona (2007): The proposed resolution is inconsistent because the return type of istreambufiterator::operator->() is specified to be pointer, but the proposed text also states that "operator-> may return a proxy." ]

[ Niels Dekker (mailed to Howard Hinnant): ]

The proposed resolution does not seem inconsistent to me. istreambuf_iterator::operator->() should have istreambuf_iterator::pointer as return type, and this return type may in fact be a proxy.

AFAIK, the resolution of 445(i) ("iterator_traits::referenceunspecified for some iterator categories") implies that for any iterator class Iter, the return type of operator->() is Iter::pointer, by definition. I don't think Iter::pointer needs to be a raw pointer.

Still I wouldn't mind if the text "operator-> may return a proxy" would be removed from the resolution. I think it's up to the library implementation, how to implement istreambuf_iterator::operator->(). As longs as it behaves as expected: i->m should have the same effect as(*i).m. Even for an explicit destructor call, i->~C(). The main issue is just: istreambuf_iterator should have an operator->()!

[ 2009-04-30 Alisdair adds: ]

Note that operator-> is now a requirement in the InputIterator concept, so this issue cannot be ignored or existing valid programs will break when compiled with an 0x library.

[ 2009-05-29 Alisdair adds: ]

I agree with the observation that in principle the type 'pointer' may be a proxy, and the words highlighting this are redundant.

However, in the current draught pointer is required to be exactly 'charT *' by the derivation from std::iterator. At a minimum, the 4th parameter of this base class template should become unspecified. That permits the introduction of a proxy as a nested class in some further undocumented (not even exposition-only) base.

It also permits the istream_iterator approach where the cached value is stored in the iterator itself, and the iterator serves as its own proxy for post-increment operator++ - removing the need for the existing exposition-only nested class proxy.

Note that the current proxy class also has exactly the right properties to serve as the pointer proxy too. This is likely to be a common case where anInputIterator does not hold internal state but delegates to another class.

Proposed Resolution:

In addition to the current proposal:

24.6.4 [istreambuf.iterator]

template<class charT, class traits = char_traits > class istreambuf_iterator : public iterator<input_iterator_tag, charT, typename traits::off_type, charT* _unspecified_, charT> {

[ 2009-07 Frankfurt ]

Move the additional part into the proposed resolution, and wrap the descriptive text in a Note.

[Howard: done.]

Move to Ready.

Proposed resolution:

Add to the synopsis in 24.6.4 [istreambuf.iterator]:

charT operator*() const; pointer operator->() const; istreambuf_iterator<charT,traits>& operator++();

24.6.4 [istreambuf.iterator]

template<class charT, class traits = char_traits > class istreambuf_iterator : public iterator<input_iterator_tag, charT, typename traits::off_type, charT* _unspecified_, charT> {

Change 24.6.4 [istreambuf.iterator], p1:

The class template istreambuf_iterator reads successive characters from the streambuf for which it was constructed.operator* provides access to the current input character, if any. [Note: operator-> may return a proxy. —_end note_] Each timeoperator++ is evaluated, the iterator advances to the next input character. If the end of stream is reached (streambuf_type::sgetc() returns traits::eof()), the iterator becomes equal to the end of stream iterator value. The default constructor istreambuf_iterator() and the constructoristreambuf_iterator(0) both construct an end of stream iterator object suitable for use as an end-of-range.