Is the typedef-name optional in a typedef declaration?
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 thetypedef
specifier, the declaration is called atypedef
declaration and
the name of eachinit-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. Thetypedef
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.
What does typedef with no type mean?
This relies on the fact that, missing type specification defaults to int
.
So, your statement
typedef t;
is the same as
typedef int t;
With the proper level of warning, compiler emits warning:
warning: type defaults to ‘int’ in declaration of ‘t’ [-Wimplicit-int]
typedef t;
^
That said, do not rely on this behaviour, "implicit int" rule has been obsolete since C99
.
Use of comma in a typedef declaration?
Yes, it is standard compliant. typedef
declarations are like normal declarations except the identifiers declared by them become type aliases for the type of object the identifier would be if the declaration had no typedef
in it.
So while
int integer, *pointer_to_integer;
declare an int
object named integer
and an int *
object named pointer_to_integer
typedef int integer, *pointer_to_integer;
would declare an int
-typed type alias named integer
and an int *
-typed type alias named pointer_to_integer
.
From a syntactical perspective, though not functionally, typedef
is just a (fake) storage classifier (like extern
, auto
, static
, register
or _Thread_local
).
Your declaration
typedef struct element {
char *data;
struct element* next;
} element, *list, elements[5];
is slightly more complicated because it also defines the struct element
data type but it's equivalent to:
struct element {
char *data;
struct element* next;
};
// <= definition of the `struct element` data type
// also OK if it comes after the typedefs
// (the `struct element` part of the typedef would then
// sort of forward-declare the struct )
/*the type aliases: */
typedef struct element
element, *list, elements[5];
-- it declares element
as a type alias to struct element
, list
as a type alias to struct element *
and elements
as a type alias to struct element [5]
.
Why can typedef'd names be used as the names of struct members?
Members of structures and ordinary variables are in different namespaces. That's why having two ordinary variables with same identifier name fails whereas if the same identifier name is used in a struct member and an ordinary variable is fine.
The C standard defines distinct namespaces:
6.2.3 Name spaces of identifiers
If more than one declaration of a particular identifier is visible at
any point in a translation unit, the syntactic context disambiguates
uses that refer to different entities. Thus, there are separate name
spaces for various categories of identifiers, as follows:
- label names (disambiguated by the syntax of the label declaration and use);
- the tags of structures, unions, and enumerations (disambiguated by following any32) of the keywords struct, union, or enum);
- the members of structures or unions; each structure or union has a separate name space for its members (disambiguated by the type of the
expression used to access the member via the . or -> operator);- all other identifiers, called ordinary identifiers (declared in ordinary declarators or as enumeration constants).
(The last two bullet items directly address this question)
Yes, typedef
'ed identifiers share the name space with ordinary identifiers. 6.7.8 Type definitions:
[...] A typedef name shares the same name space as other identifiers declared in ordinary declarators.
Why can't a typedef type be used to declare its parent class' ctors?
Similar behaviour was earlier reported as a possible Clang bug: [Bug 23107] Constructor inheritance on template not working correctly.
Richard Smith's comment on this report:
The C++ committee have discussed this case and did not intend for that syntax
to be valid. Useusing myBase::myBase;
instead to declare an inheriting constructor.
So, you should write using Base::Base;
instead of using Base::A;
. After this fix, your code compiles with Clang.
Related Topics
Sharing Precompiled Headers Between Projects in Visual Studio
How to Use Multiple Versions of Gcc
Best Library for Statistics in C++
Allocating Vectors (Or Vectors of Vectors) Dynamically
How to Compare Two Vectors for Equality Element by Element in C++
Avx2: Computing Dot Product of 512 Float Arrays
C++ Format MACro/Inline Ostringstream
Boost-Python How to Pass a C++ Class Instance to a Python Class
Convert Eigen Matrix to C Array
How to Create Std::Array with Initialization List Without Providing Size Directly
C++ #Include and #Import Difference
Why Can't We Declare a Namespace Within a Class
Error: Class Has Not Been Declared Despite Header Inclusion, and the Code Compiling Fine Elsewhere
What Is the Meaning of Template<> with Empty Angle Brackets in C++
Why Do We Have Reinterpret_Cast in C++ When Two Chained Static_Cast Can Do Its Job
Does Try-Catch Block Decrease Performance
Getting an Array of Bytes Out of Windows::Storage::Streams::Ibuffer