ostream is now a typedef of
a template; specifically, it's typedef'd as
basic_ostream<char>. Not only would the
basic_ostream template be messy to forward-declare in any
case, but you couldn't reliably forward-declare it at all, because
library implementations are allowed to do things like add their own
extra template parameters (beyond those required by the standard),
which, of course, your code wouldn't know about—one of the primary
reasons for the rule that programmers aren't allowed to write their
own declarations for things in namespace std.
All is not lost, however. The standard library
helpfully provides the header iosfwd, which contains
forward declarations for all the stream templates (including
basic_ostream) and their standard typedefs
(including ostream). So all we need to do is replace
"#include <ostream>" with "#include
<iosfwd>".
Guideline.
|
Prefer to #include
<iosfwd> when a forward declaration of a stream will
suffice.
|
Incidentally, once you see iosfwd, one
might think that the same trick would work for other standard
library templates, such as list and string. There
are, however, no comparable "stringfwd" or
"listfwd" standard headers. The iosfwd header was
created to give streams special treatment for backward
compatibility, to avoid breaking code written in years past for the
"old" nontemplated version of the iostreams subsystem.
There, that was easy. We can…
What? "Not so fast!" I hear some of you say.
"This header does a lot more with ostream than just
mention it as a parameter or return type. The inlined
operator<< actually uses an ostream object!
So it must need ostream's definition, right?"
That's a reasonable question. Happily, the
answer is: No, it doesn't. Consider again the function in
question:
inline std::ostream& operator<<( std::ostream& os, const X& x )
{
return x.print(os);
}
This function mentions an ostream&
as both a parameter and a return type (which most people know
doesn't require a definition), and it passes its
ostream& parameter in turn as a parameter to another
function (which many people don't
know doesn't require a definition either). As long as that's all
we're doing with the ostream&, there's no need for a
full ostream definition. Of course, we would need the full
definition if we tried to call any member functions, for example,
but we're not doing anything like that here.
So, as I was saying, we can get rid of only one
of the other headers just yet.