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 iterator
istreambuf_iterator doesn't have one, this must be a
defect!
Based on Greg's example, the following code demonstrates the issue:
#include <iostream>
#include <fstream>
#include <streambuf>
typedef char C;
int main ()
{
std::ifstream s("filename", std::ios::in);
std::istreambuf_iterator<char> 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 of
istreambuf_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, from
http://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 istreambuf_iterator::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 haveistreambuf_iterator::pointeras return type, and this return type may in fact be a proxy.AFAIK, the resolution of 445 ("
iterator_traits::referenceunspecified for some iterator categories") implies that for any iterator classIter, the return type ofoperator->()isIter::pointer, by definition. I don't thinkIter::pointerneeds 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 implementistreambuf_iterator::operator->(). As longs as it behaves as expected:i->mshould have the same effect as(*i).m. Even for an explicit destructor call,i->~C(). The main issue is just:istreambuf_iteratorshould have anoperator->()!
[ 2009-04-30 Alisdair adds: ]
Note that
operator->is now a requirement in theInputIteratorconcept, 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
pointeris required to be exactly 'charT *' by the derivation fromstd::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_iteratorapproach where the cached value is stored in the iterator itself, and the iterator serves as its own proxy for post-incrementoperator++- removing the need for the existing exposition-only nested classproxy.Note that the current
proxyclass also has exactly the right properties to serve as the pointerproxytoo. This is likely to be a common case where anInputIteratordoes 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<charT> > 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<charT> >
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_iteratorreads successive characters from thestreambuffor 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()returnstraits::eof()), the iterator becomes equal to the end of stream iterator value. The default constructoristreambuf_iterator()and the constructoristreambuf_iterator(0)both construct an end of stream iterator object suitable for use as an end-of-range.