This is a non-degenerate syntax that is allowed but does not provide any benefit. Most modern compilers can be triggered by a warning about this; by default they cannot. Without a typedef name, the typedef keyword is redundant; in your example, this is completely equivalent:
enum test { one };
Another place where this can happen is with the structure:
typedef struct SomeThing { int whatever; };
This is equivalent to:
struct SomeThing { int whatever; };
Note that typedef formally (or syntactically) a “storage class specifier,” such as static , extern , auto and register .
C Standard
In ISO / IEC 9899: 1999 (which is standard C) we find:
§6.7 Announcements
Syntax
declaration:
Declaration-specs init-declarator-list opt ;
declaring specifiers:
storage specifier opt
opt ad specifier specifier
type-qualifier opt qualifiers
function-specifier opt -declaration
INIT-descriptor-list:
init-declarator
init-declarator-list, init-declarator
INIT descriptor:
declarator
declarator = initializer
And (upon request):
§6.7.1 Storage class qualifiers
Syntax
storage class specifier:
typedef
extern
static
auto
register
If you track this syntax, there are many degenerate possibilities, and what you have shown is one of many.
C ++ standard
It is possible that C ++ has different rules.
In ISO / IEC 14882: 1998 (the original C ++ standard) we find in §7.1.1 "Storage class specifiers" that C ++ does not treat typedef as a storage class; the list adds mutable and excludes typedef . So, the grammar specification of typedef in C ++ is definitely different from the specification of C.
§7 Announcements
Ads indicate how names should be interpreted. Ads take the form
Statement-cl:
Ad
declaration-seq declaration
declaration:
block declaration
function definition
ad template
Explicit Presentation
Explicit Specification
binding specification
namespace-definition
block declaration:
simple declaration
asm-definition
namespace-alias-definition
using-declaration
using directive
simple declaration:
decl-specifier-seq opt init-declarator-list opt ;
...
¶5 If decl-specifier-seq contains a typedef specifier, the declaration is called a typedef declaration and the name of each init-declarator declared as typedef-name, a synonym for the type associated with it (7.1.3).
§7.1. Qualifiers [dcl.spec]
Qualifiers that can be used in an ad are
Decl specifier:
storage class specifier
type specifier
function-specifier
friend
typedef
Decl-specifier-cl:
decl-specifier-seq opt
decl-specifier
§7.1.1 Storage class qualifiers [dcl.stc]
storage class specifier:
auto
register
static
extern
mutable
§7.1.2 Function specifiers [dcl.fct.spec]
specifier function:
inline
virtual
explicit
§7.1.3 typedef specifier [dcl.typedef]
Declarations containing the decl typedef specifier declare identifiers that can be used later for naming fundamental (3.9.1) or complex (3.9.2) types. The typedef specifier should not be used in the definition of function (8.4), and it should not be combined in the decl-seq specifier with any other specifier other than the type specifier.
Bureye name:
identifier
...
In a given area, the typedef specifier can be used to override the name of any type declared in this area to indicate the type to which it already belongs. [Example:
typedef struct s { } s; typedef int I; typedef int I; typedef II;
-end example]
§7.1.4 Friend specifier [dcl.friend]
A friend specifier is used to indicate access to class members; see 11.4.
§7.1.5 Type specifiers [dcl.type]
type specifier:
simple type specifier
class-specifier
enum-specifier
specified type specifier
cv-qualifier
Since § 7 ¶5 says that typedef names come from init-declarator, and 'opt' is marked in the init-declarator list, I think it means that typedef can be omitted in C ++, just like in C.