8

From a practical point of view, I understand that both typedef and test are somewhat "superfluous" and need to be removed if we want the following code to compile:

template< typename type_t >
typedef struct tagTest
{
    int a;
} test;

However, I thought that the set of typedef declarations was a subset of the set of declarations. They just happened to have that specific decl-specifier. That was my rationalization for

typedef struct tagTest
{
    int a;
} test;

introducing the identifier test and declaring the structure tagTest. If that interpretation is correct, then the following paragraph from the standard should allow template typedef's (although not with the meaning given by the keyword using).

The declaration in a template-declaration shall — (1.1) declare or define a function, a class, or a variable, or — (1.2) define a member function, a member class, a member enumeration, or a static data member of a class template or of a class nested within a class template, or — (1.3) define a member template of a class or class template, or — (1.4) be an alias-declaration.

I cannot see error in my reasoning, yet the conclusion is illegal.

What are the relevant parts of the standard that solve the above conundrum?


UPDATE Part of the above reasoning uses the fact that typedef struct declares a structure. The typedef specifier, as far as I understand it, implies that any variables declared are really types. That is, the typedef upgrades test from a mere variable to a type that is equivalent to the declared tagTest. That is why the following code compiles (albeit with a warning).

typedef struct tagTest
{
    int a;
};
tagTest t;

One of the answers takes care of the superfluous test. But, it is possible to use typedef without a declarator because "Init-declarator-list is optional when declaring a named class/struct/union or a named enumeration"

Hector
  • 2,464
  • 3
  • 19
  • 34
  • Er... None of those cases covers it. The fact that the declaration happens to contain something that would declare a class does not mean that the declaration itself declares a class. The declaration merely defines a type. –  Jun 16 '15 at 07:44
  • @hvd In C, a typedef containing a tagged struct does declare that struct as well as defining a name that aliases it. Are you saying that C++ is different in this regard? – davmac Jun 16 '15 at 09:07
  • @davmac No, we're in agreement about the end effect of such a declaration. I'm saying that the part that causes the struct to be declared is not the declaration itself, just a sub-component of that declaration. And that applies to both C and C++. –  Jun 16 '15 at 09:10
  • @hvd got it (and I agree). So, yes, a `typedef struct` has the effect of declaring the structure, but is not itself a class (struct) declaration. – davmac Jun 16 '15 at 09:21
  • @hdv: a `typedef` declaration is a declaration that instead of declaring variables declares types. It is a declaration nonetheless. The [link shared by Marco A.](http://lists.cs.uiuc.edu/pipermail/llvmbugs/2015-January/038013.html) argues that a `typedef` declaration without declarators such as `typedef struct S { };` is legal. Because it has no declarators, the typedef is legal albeit superfluous. Since such construct does declare a `struct` sticking a template in front of it should be legal. – Hector Jun 16 '15 at 09:44
  • @Hector I understand what you are saying. There is no argument that a typedef declaration is in fact a declaration. A typedef such as the example you give also does have the effect, _indirectly_, of declaring a class (struct). I think the text you quote from the standard is trying to say that the declaration should _directly_ declare a class (and this is how compiler implementors seem to have interpreted it). But certainly, this is not explicated and is arguably ambiguous. – davmac Jun 16 '15 at 10:05
  • @davmac: Perhaps, I should get the official C++11 standard. I have the N4431 draft. The paragraph [basic.def] lists those declarations that are not definitions. As far as I can tell, that list helps to limit the set of definitions as a subset of the set of declarations. – Hector Jun 16 '15 at 10:43
  • @Hector my bad, I was skimming and somehow misread the start of that paragraph. You are right that [basic.def] it is not a complete list of declaration types; I have deleted that comment. However, my earlier comment stands, I think. – davmac Jun 16 '15 at 10:59

3 Answers3

5

Template typedefs weren't allowed pre-C++11 and with C++11 template aliases were introduced to address those issues. Cfr. C++ template typedefs and wikipedia.

Since, as you noted, the standard doesn't allow typedef to be in there, the code is invalid

alias-declaration:

 using identifier attribute-specifier-seqopt= type-id ;

typedef declarations are not alias declarations.

Furthermore you can't have a declarator if you're declaring a class template, it is explicitly forbidden by the standard

[temp]/p3

In a template-declaration, explicit specialization, or explicit instantiation the init-declarator-list in the declaration shall contain at most one declarator. When such a declaration is used to declare a class template, no declarator is permitted.

so not even the following will compile

template< typename type_t >
struct tagTest
{
    int a;
} test;

Edit:

It is nowhere specified that

typedef struct S { };

should be an error, thus both gcc and clang accept it with a warning. I assume Clang counts on [temp]/3 to issue an error in case typedef was being used with a template while gcc rejects this code immediately

template<typename T>
typedef struct S { };

cfr. clang bug 22249

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • Removing the `test` token but keeping the `typedef` specifier should be legal because the declarators are optional. – Hector Jun 16 '15 at 08:28
  • @Hector edited the question to add details for that case – Marco A. Jun 16 '15 at 08:57
  • +1 That link about clang is nice. But regarding your opening paragraph, I do not argue that `templatetypedef struct S{};` should work in the same way as the `using` keyword. I argue that the standard allow it to be legal with the same meaning as `template struct S{};`. – Hector Jun 16 '15 at 09:50
  • I'll research further in this gcc/clang difference. For now I'm more inclined into thinking that gcc is right in rejecting it. Not sure. – Marco A. Jun 16 '15 at 09:55
1

Independently from what the typedef defines, that is a typedef declaration, which is not listed in those cases:

  • [member] function
  • [member] class
  • variable
  • member enumeration
  • static data member of a class template/of a class nested within a class template
  • member template of a class or class template
  • alias declaration

And just to be clear typedef declarations are not alias declarations. Alias declaration, as specified by the grammar at §7 of the standard are:

alias-declaration:

using identifier attribute-specifier-seqopt= type-id ;

Not to mention that if this was possible, then template using declaration would not be nearly as "cool" as they are today, and there would be little to no sense to have both.

Community
  • 1
  • 1
Shoe
  • 74,840
  • 36
  • 166
  • 272
  • I think OPs point is that the text does _not_ say the declaration must _be_ a "[member] class" declaration (amongst the other types), but rather that it "shall declare or define" a class, which a typedef with a struct sub-declaration arguably does. – davmac Jun 16 '15 at 11:05
0

C does not support templates and the

typedef struct tagX {
} X;

syntax in C++ is vestigial C, there to allow continued support for C headers etc, not for use in actual C++.

The C++ syntax for the above is

struct X {};

(YMMV on brace placement)

kfsone
  • 23,617
  • 2
  • 42
  • 74