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梠ne 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.