8
namespace O { class A{}; class A; // ok typedef A K; // ok struct A; // ok(C++11): A is a class but for references and pointer it have the same meaning class K; // (1) error: K is a typedef (of a class...) } namespace U { typedef O::A A; class A; // (2) error: A is a typedef (of a class...) } 

What is the reason(s) standard C++ don't allow these cases (1 & 2) to compile?

19
  • 1
    @SethCarnegie Why? A typedef is another name for a type, all types being either basic or class/struct why can't I forward any type, even using another name for it? Commented Jan 21, 2013 at 17:47
  • 1
    you said it, a typedef is another name for a type. It would be like saying class int. The syntax of class ... requires that there not be a conflicting name. Commented Jan 21, 2013 at 17:48
  • the typedef is made at the time it is encountered, so if you want another name for a type, put the typedef after the class. Commented Jan 21, 2013 at 17:50
  • 1
    No, they don't; a header that uses names in some other header should #include that header, and if you do that, then the order in which the .cpp files #include them won't make a difference. Commented Jan 21, 2013 at 19:57
  • 2
    "Maybe the reason the standards committee didn't put it in C++ is that no one needs it"... At least two person (Klaim and me) need it :) I often want to use reference (maybe const) to std::string in my class declaration, and I have to include <string> instead of fwd declaring it (increasing compilation time). I do not think, that it's unneed feature to fwd declare typedefs Commented Jan 22, 2013 at 7:18

3 Answers 3

13

You are confused or your example doesn't show what you're asking about. In your example code you are not trying to "forward declare a typedef" (such as thing isn't possible or useful, see below) you are trying to redeclare an existing typedef-name (i.e. an alias for one type) as a completely different type.

You've already said K is a typedef for A, then you say it's a class K. Make your mind up. It's can't be both class A and class K. Both (1) and (2) fail for that same reason.

Going through these lines of the example:

class A; // ok typedef A K; // ok 

Right so far.

struct A; // ok(C++11): A is a class but for references and pointer it have the same meaning 

I don't know why you've said "C++11" here, this is OK in C++03 too. Classes and structs are the same kind of thing in C++. They are both "object types" and both "class types". For a forward declaration the class-key (i.e. struct or class) is interchangeable.

class K; // (1) error: K is a typedef (of a class...) 

K has been declared as a typedef for class A, the name can't be reused for declaring a new type in the same scope.

[Aside: C does allow the following, because struct names and typedef names are in separate namespaces:

struct A { }; typedef struct A K; // N.B. need "struct A" not just "A" struct K { }; 

But now there are two different types called struct K and K, which are unrelated. Doing this would be confusing and pretty dumb.]

But from your comments maybe that's not what you're actually trying to do anyway.

Based on your comments maybe your broken examples are misleading and what you really want to do is:

typedef class A K; // forward declare A as class and declare K as typedef for it 

This declares a typedef, for a type which is not defined yet.

It would be useless to forward-declare a typedef, you couldn't do anything with it because you wouldn't know what kind of type it was a typedef for, and there is very little you can do in C++ without knowing something about a type. Without knowing if it's an object type, reference type or function type all you can realistically do is declare another typedef for it!

Consider:

typedef K; // declares K to be a typedef K* f(); // function returning pointer to K void g(K*); // function taking pointer to K 

I think you're saying you want that to be valid, so do you expect this to work?

K* k = f(); g(k); 

That should work, right? You don't need to know the type of K because you only pass around pointers to it, right? Wrong. What if you later define K like this:

typedef int& K; 

Now f has the signature int&* f() which is invalid. You have to know what a typedef is a typedef for, so its declaration has to say what it is not just forward-declare it as a name.

Sign up to request clarification or add additional context in comments.

5 Comments

"It would be useless to forward-declare a typedef, you couldn't do anything with it because you wouldn't know what kind of type it was a typedef for, and there is very little you can do in C++ without knowing something about a type." - then why there is not "very little you can do" with forward declaration of classes. If you can forward declare a class, why you cannot forward declare a typedef? In both cases the reason is to avoid including the type's header, when the name is mentioned in another header (as a function parameter) You want only to tell the compiler, that this type(def) exists.
@Nuclear, forward declaring a class tells the compiler it's a class, that tells the compiler a lot more than "it's a type", which makes it usable in contexts where you don't need to know the class details (e.g. a pointer to a class type might have a different representation to a pointer to a function type or a pointer to a scalar type). Also, class definitions can be large and costly to include, a typedef is not. It's a single statement. You don't need to include a header for a typedef, you can just redeclare it.
'Redeclare' is the problem we're trying to avoid. It isn't "typedef A B", it's "typedef (big hairy mess) B", and you don't want to repeat that big hairy mess.
@AlanBaljeu what kind of mess? A class? Then you don't need to repeat it. Why do you need a typedef instead of just giving the class a name and using that name?
A multifaceted template instantiation, for example.
4

Let me just tackle the first error:

  1. You create class A: at this point, the name 'A' is assigned to that class; no other entities in this scope can be called 'A'.
  2. Then you typedef so that K now refers to A, so no other entities in this scope can be called 'K'.
  3. Then you try to forward declare K. Forward declaration on its own is fine, but the name K is already taken by your typedef. It has little to do with A at this point. You wouldn't be able to forward declare A either, both names are already taken by your previous uses.

What are you trying to do anyways?

6 Comments

I don't understand what is wrong with forward declaring a type after it's definition or declaration or typedef?
You already have the type defined by declaring it, why would you want to (forward) declare it again? Forward declarations are for when you don't have the full declaration available, but want to tell the compiler that the class exists. If you already have the declaration, there's no need to forward declare.
I know but I don't know the order of including of the headers containing the forward declaration, so even if I would write them in order most of the time, I easily hit cases where including multiple headers forces me to re-order them because I can't forward declare typedefs.
Well, you should make sure not to have forward declarations (or the include that has them) after your actual declarations (or the include that has <i>them</i>). And your include guards should usually take care of that anyways.
The concept of a forward declared typedef makes no sense. A typedef is a definition, it defines that symbol K is a synonym for symbol A, there's no version of that is a declaration and not a definition.
|
0

I can not found this thing in C++2003 standard. But C compiler doesn't allow such thing because typedef construction define new type, and then you try to define new type one more time via class A.

In principle usage of "forward declaration class" was allowed for two use cases:

  1. typedef-names
  2. pointer to the structure

This both operations doesn't need info about sizeof type and it's memory layout. Also in list above there is no "references" because there is no reference s in C language.

See also: (Samuel P. Harbison, Guy L.Steele] C A Reference, page 151.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.