What is the use for it? Can you not just read your data till eof?
Well, having this would have a double purpose: first, as you
know, calling eof() on a given istream object isn't a reliable
way to know if it is at eof or not; second, I would put it in
its own translation unit and insulate the very odd set of
#includes that it requires (see the part that starts with "say I
want to write this incredibly simple incantation" in
<
http://groups.google.com/group/comp.std.c++/msg/54f4a60825b15267>
)
But here's a possible context and some more specific questions.
I have a little tool (part of Breeze ---see my signature) to
generate include guards. It can do so for a file that is just
being created, of course, but even around existing content. Any
existing content must be piped to the standard in. An early
version of the tool just did something like:
out << "#ifndef " << name << '\n' ;
out << "#define " << name << '\n' ;
out << in.rdbuf() ; // (a)
out << "#endif" << std::endl ;
(where out and in are references to std::cout and std::cin).
Now, the stream inserter from a streambuf *, used at (a), sets
failbit (on the output stream) if no characters are extracted
from input.
In my case, however, this seems just a normal possibility, at
least if the reason why no characters are extracted is simply
end-of-file on std::cin; and I don't want that this causes the
subsequent out << "#endif" to do just nothing, of course.
<note>
This early version worked for me anyway, because even for a
new (empty) file I was actually piping a sequence of newlines,
in order to "space out" the #define from the closing #endif.
But obviously I didn't want to rely on this fact.
</note>
First off, I discarded the following:
out << in.rdbuf() ;
out.clear( std::ios::failbit ) ;
out << "#endif" << std::endl ;
because it clears failbit "blindly"; I suppose the standard
library could turn it on for other (valid) reasons than eof on
input.
So I replaced (a) with a call to the following function:
// A wrapper around
//
// out << in.rdbuf() [1]
//
// with the primary purpose to just skip reading if the input
// stream is already at eof (in that case, [1] sets failbit on
// the output stream, instead).
//
// Secondarily, it turns badbit on in the input stream if it has
// no attached buffer ([1] would set it in the *output* stream).
// ---------------------------------------------------------------------------
std:
stream &
transfer( std:
stream & out,
std::istream & in )
{
assert( ! out.bad() && ! in.bad() ) ;
typedef std::streambuf
buffer_type ;
buffer_type * const buf( in.rdbuf() ) ;
if ( buf == NULL ) {
in.setstate( in.badbit ) ;
} else if ( buf->sgetc() != EOF ) {
out << buf ;
}
return out ;
}
What do you think about it?
The buf->sgetc() != EOF part is a possible context where the
is_at_eof() of the original post could be used. Here's a more
concise version of it:
bool
is_at_eof( std::istream & in )
{
assert( ! in.bad() ) ;
return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() == EOF ;
}
Please, disregard the fact that it's not really necessary, here.
Indeed I'm not using it yet for the include_guard tool, but it
brings some questions on which I'd like your opinion. I know
that rivers of ink... ehm... gazillions of keystrokes have been
poured on the subject of (predictive) eof over the C++
newsgroups, so I'm cautious.
My main doubts are:
- If in.eof() is true, is it correct that I just ignore it and
go taking sgetc()? (More data might have become available
after eof was set, of course, but the I/O library is complex
enough that I wonder if going on anyway and attempt a sgetc()
doesn't lead to UB.)
- if rdbuf() is null the function returns false: indeed it would
not be correct to say that the stream is "at eof", however it
probably makes more sense to "invert the logic" to
bool has_more_data( std::istream & in )
{
assert( ! in.bad() ) ;
return in.rdbuf() != NULL
&& in.rdbuf()->sgetc() != EOF ;
}
? Should we assert if rdbuf() is null? Should we set badbit
instead?