views:

1337

answers:

4

Good evening :)

I'm playing around with g++ and makefiles. I've gotten to this point:

foo.h:

#ifndef _FOO_H_
#define _FOO_H_

#include "bar.h"

class foo {
private:
    bar something;
public:
    bool start();
    bool stop();
};

#endif // _FOO_H_

Foo.h is eventually included in my main cpp file so I can set things in motion by calling start/stop.

void somewhere() {
    foo* hihi = new foo;
    hihi->start();
    delete hihi;
}

Then there's bar.h:

#ifndef _BAR_H_
#define _BAR_H_

class bar {

};

#endif // _BAR_H_


g++ doesn't seem to like it however:

g++  (some_flags) -c main.cpp
In file included from main.cpp:2:
foo.h:8: error: ‘bar’ does not name a type

I'm using makefiles, and tried a combination of things like:

main.o: main.cpp foo.h bar.h

Even though I don't think I should have to add bar.h here, shouldn't including it in foo.h be enough?

To clarify, this is roughly how it's set up now (yes I know this can be done in a more efficient manner):

main.o: main.cpp foo.h
    $(CC) $(CFLAGS) -c main.cpp

foo.o: foo.h foo.cpp
    $(CC) $(CFLAGS) -c foo.cpp

bar.o: bar.h bar.cpp
    $(CC) $(CFLAGS) -c bar.cpp

What's going on? I figure it's something I'm missing about g++ and the way it handles header includes, point me in the right direction please!

edit - found the solution:

Doh! I feel dumb right now. Was messing around with boost::asio and kind of forgot I still left this on top of my headers somewhere: using boost::asio::ip::tcp;

Let's just say there's a boost::asio::ip::tcp::bar function :D

Oh well, thanks anyway!

A: 

In the main.cpp, you'll need to add the following line at the top of the file:

#include "foo.h"
Tommy Hui
bar.h is included in foo.h which is included in main.cpp
Daniel
If that line were missing, then we wouldn't see a message about line 8 of foo.h as the "file included from main.cpp:2."
Rob Kennedy
+1  A: 

Double check everything. If you include bar.h into foo.h, the compiler should not raise up an error. Do you include foo.h from bar.h? Better don't do this because that would cause a circular dependency between headers, which will cause that kind of bugs.

Also check for spelling of header guards. This can be a common source of annoyance:

#ifdef _BAR_H_ // OOPS! we wanted #ifndef
#define _BAR_H_

class bar {

};

#endif // _BAR_H_

In addition, you should avoid putting the underscore before your header guard macro name. These names are reserved to the compiler. Call it INCLUDED_BAR_H or just BAR_H_ instead.

Johannes Schaub - litb
This wasn't exactly the solution to my problem, but +1 for the info, thanks.
Daniel
+1  A: 

Tommy Hui and litb have already pointed to two probable causes; here's some background information that will hopefully come in useful.

First off, this has nothing to do with makefiles. A makefile is just a convenience thing that calls g++ for you, nothing more.

This stuff with header files can be a bit tricky to understand at first, especially once you get into circular dependencies. It really helped me to realize these three things:

  • A #include is nothing more than a copy/paste operation, inserting the contents of the included file at that point.
  • Everything must have been declared before it is used. Sometimes, when circular dependencies crop up, you might need to predeclare a class (e.g. class bar;) in another header.
  • If, at the point of usage, any more information about the type is needed than just its existence, then the type's definition is needed as well. This goes for e.g. calling of a method on an object of that type, but also for including a field of that type! (Not for a pointer to an object of that type, though, because pointers are all the same size.)
Thomas
This wasn't exactly the solution to my problem, but +1 for the info, thanks.
Daniel
+2  A: 

Was messing around with boost::asio and kind of forgot I still left this on top of my headers somewhere: using boost::asio::ip::tcp;

Let's just say there's a boost::asio::ip::tcp::bar function

Dan Saks explains some reasons why you should typedef your class names, even though it might seem redundant.

Well, you've run into real life situation where typedefing a class would have probably helped you find your problem a little easier:

 class bar {
 // ...
 };
 typedef class bar bar;

Generates this more meaningful message if there's a function named bar() already declared:

In file included from C:\temp\foo.h:4,
                 from C:\temp\test.cpp:4:
C:\temp\bar.h:7: error: `typedef class bar bar' redeclared as different kind of symbol
C:\temp\test.cpp:1: error: previous declaration of `void bar(int)'
C:\temp\bar.h:7: error: declaration of `typedef class bar bar'
Michael Burr