views:

364

answers:

4

So I'm going through the first tutorial in O'Reilly's iPhone 3D Programming book. At this point in the tutorial, it pulls all the OpenGL ES stuff into a seperate c++ interface. I have followed the book to the letter, as far as I can tell, yet I can't seem to figure out this compiler error. I'm fairly new to C++ (mostly C# in the past), so I'm sure it's something stupid.

Below is the current state of all the relevant files.

I have a c++ header file called IRenderingEngine.hpp with the following contents:

enum DeviceOrientation {
    Unknown,
    Portrait,
    PortraitUpsideDown,
    LandscapeLeft,
    LandscapeRight,
    FaceUp,
    FaceDown,
};

struct IRenderingEngine* CreateRenderer1();

struct IRenderingEngine {
    virtual void Initialize(int width, int height) = 0; //Compiler error "expected specifier-qualifier-list before 'virtual'
    virtual void Render() const = 0;
    virtual void UpdateAnimation(float timeStep) = 0;
    virtual void OnRotate(DeviceOrientation newOrientation) = 0;
    virtual ~IRenderingEngine() {}
};

I have an objective-c/c++ header file called GLView.h that looks like this:

#import "IRenderingEngine.hpp"
#import <OpenGLES/EAGL.h>
#import <QuartzCore/QuartzCore.h>

@interface GLView : UIView {
    EAGLContext* m_context;
    IRenderingEngine* m_renderingEngine; //Compiler error: Expected specifier-qualifier-list before "IRenderingEngine"
    float m_timeStamp;
}

- (void) drawView: (CADisplayLink*) displayLink;
- (void) didRotate: (NSNotification*) notification;

@end

And finally, a GLView.mm file with a barebones implementation:

#import "GLView.h"


@implementation GLView

+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

- (id)initWithFrame:(CGRect)frame {
    return self;
}

- (void) drawView:(CADisplayLink *)displayLink
{

}

-(void) didRotate:(NSNotification *)notification
{

}

@end
A: 

I believe this line is causing the error:

struct IRenderingEngine* CreateRenderer1();

I'm not quite sure what you're trying to do there, but I think it should be removed entirely.

Cogwheel - Matthew Orlando
I thought the same thing, but the book specifically leaves it in the place I left it above, and moving it below the IRenderingEngine struct didn't change the compiler error reported. The idea presented in the book is that CreateRenderer1() will create an OpenGL ES 1.1 implementation, with another one added later called CreateRenderer2() that implements OpenGL ES 2.0 (for fallback purposes).
Dusda
Well, it certainly has to go after the definition of the IRenderingEngine struct as fbrereto mentioned, but even then it's not really valid. Maybe it's supposed to be a function pointer? e.g. `struct IRenderingEngine (*CreateRenderer1)()`
Cogwheel - Matthew Orlando
I've tried commenting **struct IRenderingEngine* CreateRenderer1()** out entirely (I'm not actually using it yet anyway), and it hasn't had any effect.
Dusda
Maybe this'll help? http://answers.oreilly.com/topic/631-how-to-get-c-and-objective-c-to-play-nicely-in-xcode/
Cogwheel - Matthew Orlando
I found that while googling around haven't tried it yet because the book does it differently. I'll give it a shot real quick though.
Dusda
Well, I don't think I can be much more help at this point. I don't do any iphone dev, i just know enough about C++ to see what was wrong at that point. Good luck!
Cogwheel - Matthew Orlando
A: 

The line

struct IRenderingEngine* CreateRenderer1();

Must come after the declaration of the IRenderingEngine class. (Also, if you intended to use the variable as a pointer to that structure type you should omit the parentheses in its declaration.)

For your other error I think you want to prepend the line with struct.

fbrereto
The other error might go away once the first problem is fixed?
Cogwheel - Matthew Orlando
I added **struct** to the second line that was breaking and it removed the compiler error. However, the book explicitly defines the line as "IRenderingEngine* m_renderingEngine;", and since I'm not well-versed in c++ I'm afraid to question the syntax :(.
Dusda
Oh, and the **struct** change to the second error did not remove the first. It's still complaining about the struct IRenderingEngine in the .hpp file.
Dusda
+1  A: 

This error message e.g. occurs if one of your two headers gets included in a plain Objective-C source file, which doesn't know anything about handling C++ code.

To allow GLView to be used from plain Objective-C sources, use only a forward declaration for the rendering engine and don't include the C++ header in GLView.h:

// GLView.h:
struct IRenderingEngine;
@interface GLView : UIView {
    struct IRenderingEngine* m_renderingEngine;
// ...
@end

// GLView.mm:
#import "IRenderingEngine.hpp"
// ... etc.

Alternatively you can use opaque pointers for wrapping C++ instances to keep the Objective-C interface more stable, see e.g. Rob Napiers post on the subject.

When this is fixed, you still need to fix the declaration for CreateRenderer1() as others pointed out - either forward-declare struct IRenderingEngine; before the function or just move it after the definition of the struct.

Georg Fritzsche
I have no plain objective-c files (except for main.m, which would have exploded earlier when I had the entire OpenGL implementation in GLView.mm). If all else fails I will try this suggestion.
Dusda
@Dusda: You have to include/import `GLView.h` somewhere to use it? Either all source files including it are Objective-C++ or you write `GLView.h` so that plain Objective-C sources can use it too.
Georg Fritzsche
@Dusda: I'm telling you that you *shouldn't* import it in `GLView.h`. If you only include `GLView.h` in `GLView.mm` you shouldn't have problems after fixing the problem with `CreateRenderer1()` - but that error strongly suggests that you *are* including `GLView.h` in a `.m` file.
Georg Fritzsche
Okay, I removed the #import reference to IRenderingEngine.hpp from GLView.h, added **struct IRenderingEngine;** to GLView.h, and then added the **#import "IRenderingEngine.hpp"** to GLView.mm. It compiles now, albeit with a complaint about CreateRenderer1() (I'm assuming because I haven't written an implementation for it yet). I think that worked.
Dusda
Yep, that worked. I was able to finish the rest of the app with no trouble. I'm probably going to pick up a C++ book now, so I can understand how forward declarations work, among other things. Thanks dude.
Dusda
+2  A: 

You need to rename HelloArrowAppDelegate.m to a .mm file. It states in the book on page 20 (middle section with the paws bullet point). I missed that section and had the same problem. After changing the file to .mm the program worked.

Kelvin