keyword "class" is inconsistent?

class c {int i,j,k;};
class c;

int main(){}

this simple program has no problem to get compiled. for example first line could be in a header and someone decided to include it even though class c gets pre-declared.

namespace delme{
class c {int i,j,k;};
};
typedef delme::c c;

class c;

int main(){}

this fails to compile:
delme-doubleclass.c:6:7: error: using typedef-name 'c' after 'class'
6 | class c;
| ^
delme-doubleclass.c:4:18: note: 'c' has a previous declaration here
4 | typedef delme::c c;
| ^

why? the maintainer of the header-file simply moved the class into the namespace and typedefs it in global scope for backward compatibility. but with this program the compatibility got broken anyway!
is there any way to perform the global-scope alias so the program compiles?
Basically, a typedef'd token can't be used in a forward declaration.
Note that this also fails to compile:
1
2
3
4
5
6
7
class c {};

typedef c d;

class d;

int main(){}


https://stackoverflow.com/questions/2263154/using-typedef-name-as-class-on-a-forward-declaration/10487290

Why? I dunno, maybe someone else can explain it better. Also read the SO post linked above.
Billy ONeal wrote:
1
2
typedef Test Test1;
class Test1;

fails because the typedef statement serves as the declaration for the Test1 type.

Basically, when the compiler sees the typedef, it remembers that Test1 is a synonym for Test. Then when it sees class Test1;, it thinks there's a new type you are declaring. But it can't treat that as a declaration because the name Test1 is already being used by the typedef.


Edit:
Furthermore, it's redundant, is it not?
In order to even have "typedef a b;" be valid, the compiler already needs to know that a is a type. So what advantage would this have, even if it did compile?

In other words, there is no need for the class c; in your 2nd code if there was already a typedef before it.
(But I see what you're saying, it's unfortunate that simply adding that line is harmful to the compilation.)
Last edited on
In other words, there is no need for the class c; in your 2nd code if there was already a typedef before it.
(But I see what you're saying, it's unfortunate that simply adding that line is harmful to the compilation.)


This is essentially correct.

typedef a b;

creates a definition for b which is the same as a, which naturally includes an implied declaration of b as a type.

If, then,

class b;

is written, it is an attempt to create a declaration of type b, which as already been declared and defined with the previous typedef, creating a conflict (not an inconsistency).

In other words, it is similar to trying:

1
2
3
4
5
6
7
8
class A
{ int x;
};


class A
{ float y;
};


Here, the second "class A" conflicts with the previous declaration/definition of class A. If permitted, the second would make the first disappear.

So, when a typedef creates a declaration/definition of a type, and then an attempt to declare a new type of the same name appears later, it is a similar conflict.

In part this means the compiler does consider a small distinction between the typedef which creates a declaration/definition of a type and a forward class declaration, because, as some reasoning I read long ago, it is all too easy to confuse the situation where, say, b (from above) is created and later a declaration which forward declares what the programmer may think is a new type 'b', when such a type has already been created.

When a typedef is created which transports a declaration over a namespace, this could be confusing:

1
2
3
4
5
6
7
namespace delme{
class c {int i,j,k;};
};
typedef delme::c c;

class delme::c;
class c;


If allowed, the last two lines suggest the forward declaration of the exact same class, where the second was transported over the namespace via typedef.

The first one is allowed, as it is merely a forward declaration that matches.

The second isn't because the compiler "sees" 'c' differently, where the fact it is a typedef is incorporated in what it recognizes as the type of 'c'. It 'sees' 'c' as having the type "delme::c".

Last edited on
Out of curiosity:
1
2
3
4
5
6
7
8
9
class c {};

using d = c;
class d;

typedef c e;
class e;

int main(){}

1
2
3
4
5
4:7: error: using typedef-name 'using d = class c' after 'class'
3:12: note: 'using d = class c' has a previous declaration here

7:7: error: using typedef-name 'e' after 'class'
6:11: note: 'e' has a previous declaration here

Verbosity.


If you just want the "plain name":
1
2
3
4
5
6
7
8
namespace delme{
  class c {int i,j,k;};
};

int main() {
  using delme::c;
  c x;
}
It is not clear what you are expecting this to do.

The standalone class c; declaration in your code declares a global type ::c. That's how declarations work in C++. They introduce new entities into the scope. That's a fundamental property of the language.

At the same time you are introducing into the global namespace a typedef-name c that is supposed to refer to delme::c.

So, after all that, what is name c supposed to stand for? For the global ::c that you declared and never defined? Or for delme::c?
Last edited on
Topic archived. No new replies allowed.