views:

171

answers:

5

Hello all,

I have a problem which is either something I have completely failed to understand, or very strange. It's probably the first one, but I have spent the whole afternoon googling with no success, so here goes...

I have a class called Schedule, which has as a member a vector of Room. However, when I compile using cmake, or even by hand, I get the following:

In file included from schedule.cpp:1:
schedule.h:13: error: ‘Room’ was not declared in this scope
schedule.h:13: error: template argument 1 is invalid
schedule.h:13: error: template argument 2 is invalid
schedule.cpp: In constructor ‘Schedule::Schedule(int, int, int)’:
schedule.cpp:12: error: ‘Room’ was not declared in this scope
schedule.cpp:12: error: expected ‘;’ before ‘r’
schedule.cpp:13: error: request for member ‘push_back’ in ‘((Schedule*)this)->Schedule::_sched’, which is of non-class type ‘int’
schedule.cpp:13: error: ‘r’ was not declared in this scope

Here are the relevant bits of code:

#include <vector>

#include "room.h"

class Schedule
{
  private:
    std::vector<Room> _sched; //line 13
    int _ndays;
    int _nrooms;
    int _ntslots;
  public:
    Schedule();
    ~Schedule();
    Schedule(int nrooms, int ndays, int ntslots);
};
Schedule::Schedule(int nrooms, int ndays, int ntslots):_ndays(ndays), _nrooms(nrooms),_ntslots(ntslots)
{
  for (int i=0; i<nrooms;i++)
  {
    Room r(ndays,ntslots);
    _sched.push_back(r);
  }
}

In theory, g++ should compile a class before the one that includes it. There are no circular dependencies here, it's all straightforward stuff. I am completely stumped on this one, which is what leads me to believe that I must be missing something. :-D

Edit:
The contents of room.h from the comments below:

#include <vector>  
#include "day.h" 

class Room 
{ 
private: 
   std::vector<Day> _days; 

public: 
   Room(); 
   Room(int ndays, int length); 
   ~Room(); 
};
A: 

In theory, g++ should compile a class before the one that includes it.

g++ should be able to compile your source files in any order it sees fit. The order it includes headers into your source is set by the order of your #include statements.

The most likely case is that the class name is room, and not Room. Next likely is that the name is some other thing besides Room. Less likely is that it is in a namespace other than the root namespace.

EDIT: Okay, if it's none of those, make sure that the room.h that is being included is your room.h and not some other room.h. Nothing like editing the wrong copy of a file to waste your day.

EDIT 2: I'm assuming your header files have the usual include-once structure:

#ifndef schedule_h
#define schedule_h

// header file code goes here.

#endif

... and that you omitted it for brevity.

EDIT 3: I just copied the code you gave to a new directory, and created a dummy day.h file with the contents:

typedef int Day;

I then used g++ -c -o schedule.o schedule.cpp to build it and got no errors. Therefore the error is something we're not seeing.

Edit 4: Okay, sanity check time. Look at the top of room.h and make sure it says

#ifndef room_h

and not

#ifdef room_h
Mike DeSimone
I rechecked, just in case. Room is spelled correctly. There are no namespace definitions, so it is using std.
ravloony
@ravloony: it doesn't use the std namespace, it uses the global namespace.
Bill
I did indeed omit it for brevity.I'm going to copy all the source to a clean folder and try again.
ravloony
@Bill: You're absolutely right. That is what I meant. Sorry.
ravloony
@Mike DeSimone: Copying all the code to a clean source folder gives the exact same error.
ravloony
@ravloony: That doesn't necessarily mean it's using the code from your clean folder, if there's a directive setting an include path from outside your folder.
Mike DeSimone
@Mike DeSimone: The error was the include guards. I had renamed another class from Room to something else using my ide, which had not changed the include guards. So Room was never getting included, hence the error.So it was something rather obvious.Thank you all for your help!
ravloony
Morals of the story: 1) Be really careful about what code you choose to omit from posting, and 2) "Psychic debugger sense" brings in the up votes, even if it's wrong, and I need to get some of that sense. ^_^
Mike DeSimone
A: 

I can't tell from your post of schedule.h/.cpp but it looks like you might have the #include "room.h" in schedule.cpp but your schedule.h is making use of class Room. #include "room.h" should be in schedule.h if this is the case.

Or you can use forward declaration in schedule.h.

Robb
The include line is in schedule.h
ravloony
A: 

It may not matter, I but I see no include guards in your headers. Shouldn't matter, but just to cover any angle...

Michael Dorgan
They were omitted for brevity. (See third comment on my answer.) Also, in this case where the include tree is pretty much a line, they don't make a difference.
Mike DeSimone
@Michael Dorgan: It was an include guard error. See below for details. Thank you!
ravloony
A: 

What does Room.cpp look like?

Also.. I've never had any problems with this, but maybe you forgot to put an extra line at the bottom of your header file?

Marlon
+4  A: 

Even though you've omitted some important code (namely, the contents of day.h), my psychic debugger sense tells me that you have a circular dependency in your header files:

// schedule.h
#include "room.h"

// room.h
#include "day.h"

// day.h
#include "schedule.h"

This is bad. In order to break the circular dependency, you need to figure out which file doesn't need to know the concrete implementation details of the others. This is done using forward references. For example, I can see that your definition of the Room class doesn't actually need to know what sizeof(Day) is for the class definition, so you can rewrite it as follows:

#include <vector>
// do NOT include day.h

class Day;  // forward declaration
class Room 
{ 
private: 
   std::vector<Day> _days; 

public: 
   Room(); 
   Room(int ndays, int length); 
   ~Room(); 
};

Now room.h doesn't depend on day.h, breaking the circular dependency. Of course, the implementation file room.cpp will still have to include day.h.

Adam Rosenfield
+1 Thinking the same thing.
JRL
I don't think you can have a vector of an incomplete type. Also, how would a circular dependency produce the error the OP is actually getting? If the include guards are present as he says then the include inside day.h would fail, and you'd expect to get an error in day.h.
Mike Dinsdale
@Mike: Yes, you can have a vector of an incomplete type, so long as you don't invoke any methods on it. Try it out. Of course, in order to be useful, you'll have to complete the type, but that can be done in the cpp file instead of the header file.
Adam Rosenfield
@Mike: A circular dependency could produce the error because it depends on the which header is included first in the source file. If schedule.cpp first includes room.h, which includes day.h, which includes schedule.h, which tries to include room.h again, then that re-inclusion will not produce any output (since the header guard is now defined), so when the definition of the `Schedule` class is reached, room.h has technically been included, but the `Room` class has not yet been defined because of the circular dependency, resulting in OP's error.
Adam Rosenfield
@Adam: Thanks, you're right about the vector! (I did try it, but I tried to instantiate one, which doesn't work :) It does work as a member though as you say, presumably the class needs to be defined before the constructor plus any place you call methods on the vector).
Mike Dinsdale
@Adam - I'm not sure about your second point in this case, because schedule.hpp is included from line 1 of schedule.cpp.
Mike Dinsdale
@Mike: Where does he say that schedule.h (not hpp, btw) is included on line 1 of schedule.cpp?
Adam Rosenfield
@Adam: "In file included from schedule.cpp:1:" (yes, it's h though, sorry about that ;))
Mike Dinsdale
@Mike: Oh ok, hmm. We'll really have to see what the entirety of schedule.h, room.h, and day.h (and possibly any other headers that includes) to diagnose the problem.
Adam Rosenfield
It was an include guard problem. See below. Serves me right for trusting my IDE to do The Right Thing (tm)Thanks!
ravloony