14

I'm creating a protocol, and one of the parameters to a method I'm defining is a CMTime*. I would like to forward declare CMTime as opposed to including it. However, I've tried @class CMTime and it complains that it is redefined elsewhere as a different type of symbol. Documentation says it's a struct. I've tried forward declaring it as

struct CMTime;

but it still is complaining that it doesn't know what it is.

Any ideas what I'm doing wrong?

justin
  • 101,751
  • 13
  • 172
  • 222
user1186226
  • 141
  • 1
  • 3
  • 2
    Unfortunately, it is declared using an anonymous struct. This means you either have to copy the entire declaration (and hope it never changes), or just include the header. – ughoavgfhw Feb 02 '12 at 21:59
  • 1
    @ughoavgfhw copying it isn't good (chances are, both declarations will end up in the same TU).other than that, I think that qualifies as a specific answer, considering how `CMTime`'s been declared. – justin Feb 02 '12 at 22:06
  • @Justin I only suggested it because he said he wasn't going to include the header, but now that I think about it, he was getting an error that it had already been defined when trying to create a class, which would suggest the header was already included. If someone can explain that, I might post it as an answer. – ughoavgfhw Feb 02 '12 at 22:12
  • @ughoavgfhw presumably, it was because the OP forgot or omitted the `struct` tag when used. `void foo(CMTime*)` vs. `void foo(struct CMTime*)`. – justin Feb 02 '12 at 22:56
  • You should accept justin's answer. – Arseniy Banayev Apr 09 '13 at 16:37

3 Answers3

18

A source compiled as ObjC has the same rules as C in this regard.

A source compiled as ObjC++ has the same rules as C++ in this regard.

@class MONClass; is a forward declaration of an ObjC type. Do not use it for structs.

struct t_mon_struct; is a forward declaration of a named C or C++ struct. Do not use it for ObjC types. Technically, the compiler allows you to also forward declare a C++ class as a struct (provided of course the class is also declared in the global namespace).

Thus, the root of the semantics all boil down to C (assuming this is an ObjC translation). I'll stop mentioning ObjC and C++ now.

There are some common sources of complexity here:

  • the struct namespace
  • the struct's declaration
  • avoiding multiple definitions of labels

struct t_mon_struct; is a forward declaration of a tagged struct. Specifically, that is whose name exists in the struct namespace.

a tagged struct which exists in the struct namespace:

struct t_mon_struct { int a; };

an anonymous struct with a typedef in the global namespace:

typedef struct { int a; } t_mon_struct;

a tagged struct with a typedef in the global namespace:

typedef struct t_mon_struct { int a; } t_mon_struct;

CMTime is declared as follows:

typedef struct
{
    CMTimeValue    value;
    CMTimeScale    timescale;
    CMTimeFlags    flags;
    CMTimeEpoch    epoch;
} CMTime;

Specifically, the global typedef label CMTime is bound to an anonymous struct in the struct namespace, and may not be referenced unless its declaration is visible.

Had CMTime been declared:

typedef struct CMTime
{
    CMTimeValue    value;
    CMTimeScale    timescale;
    CMTimeFlags    flags;
    CMTimeEpoch    epoch;
} CMTime;

then you could have gotten by using a forward declaration struct CMTime:

struct CMTime;
void foo(struct CMTime*);

Since it wasn't declared that way, you'll need to #include its declaration, or devise a workaround.

The complications worsen when the the struct's typedef is distinct from its tag. You can't bind to or redeclare a typedef (in C). However, you can sneak around it by using the name in the struct namespace -- which some library authors consider as being private.

justin
  • 101,751
  • 13
  • 172
  • 222
1

Just adding typedef before the struct does the trick for me.

typedef struct CMTime;
jowie
  • 7,877
  • 8
  • 52
  • 92
0

If you want the files which have the forward declaration to know about the contents of the struct, they need to either import a header (it can be in multiple places) where it is defined. You can forward declare a struct if you do not need to access its properties, but that is the extent of it.

jrtc27
  • 8,386
  • 3
  • 33
  • 68