Advertisement

Forward references

Started by June 09, 2000 02:58 PM
6 comments, last by Kylotan 24 years, 6 months ago
Ok, this fails to compile in both Visual C++ and Borland C++ Builder, so I assume it''s me that''s wrong and not the compilers. But I don''t understand why. Surely the forward declaration shouldn''t interfere with the actual definition?

// filing.h //////////////////////////////////////////////////

// forward reference to avoid having to include <istream>
class istream;

void Read(istream& file, int& v);
void Read(istream& file, long& v);
void Read(istream& file, short& v);


// filing.cpp ///////////////////////////////////////////////////
#include "filing.h"
#include 
using std::istream;

void Read(istream& file, int& v)
{
    file >> v;
}

void Read(istream& file, long& v)
{
    file >> v;
}

void Read(istream& file, short& v)
{
    file >> v;
}
 
The error is: using-declaration causes a multiple declaration of ''istream'' Now, I tried it with another class (std::string) and that gave a similar error (it was typedefed to String, so it just said "multiple definition of string" or something). Why does this happen? Is it because istream is a template class or something? Is there a way around it?
I think what is happening is this: you are trying to declare a global class, then putting the std namespace into the global namespace, which causes a naming collision because there are now two `global namespace::string's (even though one is not defined yet).

In that case, try this:


namespace std {
class istream;
};



That might not work either, considering istream is probably just a typedef for some variety of basic_istream. If that doesn't work, I'm not sure what you can do -- as far as I know you can't forward declare template classes (but maybe that's been changed?).



- null_pointer
Sabre Multimedia


Edited by - null_pointer on June 9, 2000 5:00:24 PM
Advertisement
What is in your filing header - are you including something in there that declares istream?
I believe in VC++ you can open a brand new .cpp file and type

std::istream::read

and it know whats going on. So it might be pre-declaring something behind your back.

-Mezz
A very easy way to have the appropriate forward declarations for the stream classes without having to include the whole class headers themselves is this:

    #include <iosfwd>    


That header file was specifically created for forward declarations, to help reduce compile times and such.

---- --- -- -
Blue programmer needs food badly. Blue programmer is about to die!
OK, it -is- the fact that they are templates, as it works for non-template classes. Which is stupid, since if the C++ standard library pretty much relies on next to everything you use being a template in some form or other, this means you have to #include everything in your headers, even when just using pointers or references. This extremely bad on compile times.

Mossmoss, the <iosfwd> header works, thanks. Although having to include 44k of <iosfwd> compared to 15 bytes of 'class istream;' is very annoying. It's also just a hacked fix for these particular classes. The std::string usage, which I omitted from the original example for clarity but mentioned, still gives me these errors so I have to include it in its entirety anyway. And, guess what header file <string> includes? You guessed it, <istream>. Thus defeating the entire object. What a crap system.

Thanks all.

Edited by - Kylotan on June 9, 2000 10:16:51 PM
The problem is that you created a forward declaration of class istream; however, istream is itself a typedef, not a class declaration.

So in order to get your forward declaration you need:

template <class _E, class _Tr = char_traits<_E> > class basic_istream;
typedef basic_istream<char, char_traits<char> > istream;

for the forward declarations and the typedefs. And furthermore you need to class defination of the char_traits class.

For forward declaring the string class you need:

template <class _E, class _Tr = char_traits<_E>, class _A = allocator<_E> > class basic_string;
typedef basic_string<char, char_traits<char>, allocator<char> > string;

as well as the class definition for the allocator class.

I suppose you could get away with doing forward declarations for the char_traits and the allocator classes though...

template <class _Ty> class allocator;
template <class _E> struct char_traits;
Advertisement
I don't see why it should matter. At no point did I use an instance of the class, only a reference. Surely a reference will just be a simple 4-byte pointer like all the rest, no matter how the class is defined? Why does it need to know more than just that the class exists?

Edited by - Kylotan on June 10, 2000 1:24:08 PM
It doesn''t need to know anything more than the class exists. Here''s the deal. With the forward reference
class istream;
You entered into the symbol table a that there is a class type named istream. When the later typedef is made there is a collision because the typedef states that istream is an alias for basic_istream<char, char_traits<char> > and is therefore not a separate class. This fails under the structural equivelence for C++ and so causes a type error.

So the problem is that you have incompatible definitions for the meaning of the symbol "istream".

This topic is closed to new replies.

Advertisement