It is a degenerate syntax that is allowed but provides no benefit. Most modern compilers can be provoked into emitting a warning about it; by default, they may not. Without the typedef name, the keyword typedef
is superfluous; in your example, it is completely equivalent to:
enum test { one };
Another place where it can occur is with a structure:
typedef struct SomeThing { int whatever; };
This is equivalent to:
struct SomeThing { int whatever; };
Note that typedef
is officially (or syntactically) a 'storage class specifier', like static
, extern
, auto
and register
.
C Standard
In ISO/IEC 9899:1999 (that's the C standard), we find:
§6.7 Declarations
Syntax
declaration:
declaration-specifiers init-declarator-listopt;
declaration-specifiers:
storage-class-specifier declaration-specifiersopt
type-specifier declaration-specifiersopt
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiersopt
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator
declarator = initializer
And (as requested):
§6.7.1 Storage-class specifiers
Syntax
storage-class-specifier:
typedef
extern
static
auto
register
If you track through that syntax, there are a lot of degenerate possibilities, and what you showed is just one of the 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 grammatical specification of typedef
in C++ is definitely different from the C specification.
§7 Declarations
Declarations specify how names are to be interpreted. Declarations have the form
declaration-seq:
declaration
declaration-seq declaration
declaration:
block-declaration
function-definition
template-declaration
explicit-instantiation
explicit-specialization
linkage-specification
namespace-definition
block-declaration:
simple-declaration
asm-definition
namespace-alias-definition
using-declaration
using-directive
simple-declaration:
decl-specifier-seqopt init-declarator-listopt ;
...
?5 If the decl-specifier-seq
contains the typedef
specifier, the declaration is called a typedef
declaration and
the name of each init-declarator
is declared to be a typedef-name,
synonymous with its associated type
(7.1.3).
§7.1 Specifiers [dcl.spec]
The specifiers that can be used in a declaration are
decl-specifier:
storage-class-specifier
type-specifier
function-specifier
friend
typedef
decl-specifier-seq:
decl-specifier-seqopt
decl-specifier
§7.1.1 Storage class specifiers [dcl.stc]
storage-class-specifier:
auto
register
static
extern
mutable
§7.1.2 Function specifiers [dcl.fct.spec]
function-specifier:
inline
virtual
explicit
§7.1.3 The typedef specifier [dcl.typedef]
Declarations containing the decl-specifier
typedef
declare identifiers that can be used later for naming
fundamental (3.9.1) or compound (3.9.2) types. The typedef
specifier shall not be used in a function-definition
(8.4), and it shall not be combined in a decl-specifier-seq
with any other kind of specifier except
a type-specifier.
typedef-name:
identifier
...
In a given scope, a typedef specifier can be used to redefine the name of any type declared in that scope
to refer to the type to which it already refers. [Example:
typedef struct s { /* ... */ } s;
typedef int I;
typedef int I;
typedef I I;
—end example]
§7.1.4 The friend specifier [dcl.friend]
The friend specifier is used to specify access to class members; see 11.4.
§7.1.5 Type specifiers [dcl.type]
type-specifier:
simple-type-specifier
class-specifier
enum-specifier
elaborated-type-specifier
cv-qualifier
Since §7 ?5 says that typedef
names come from the init-declarator and the init-declarator-list is tagged 'opt', I think that means that the typedef
name can be omitted in C++, just as in C.