From what I have understood, declarations/initializations in C++ are statements with \'base type\' followed by a comma separated list of declarators.
Consider the follow
This is specified in [dcl.dcl] and [dcl.decl] as part of the simple-declaration
* and boils down to differences between the branches in ptr-declarator
:
declaration-seq: declaration declaration: block-declaration block-declaration: simple-declaration simple-declaration: decl-specifier-seqopt init-declarator-listopt ; ---- decl-specifier-seq: decl-specifier decl-specifier-seq decl-specifier: type-specifier ← mentioned in your error type-specifier: trailing-type-specifier trailing-type-specifier: simple-type-specifier cv-qualifier ---- init-declarator-list: init-declarator init-declarator-list , init-declarator init-declarator: declarator initializeropt declarator: ptr-declarator ptr-declarator: ← here is the "switch" noptr-declarator ptr-operator ptr-declarator ptr-operator: ← allows const * cv-qualifier-seq opt cv-qualifier: const volatile noptr-declarator: ← does not allow const declarator-id declarator-id: id-expression
The important fork in the rules is in ptr-declarator
:
ptr-declarator:
noptr-declarator
ptr-operator ptr-declarator
Essentially, noptr-declarator
in your context is an id-expression
only. It may not contain any cv-qualifier
, but qualified or unqualified ids. However, a ptr-operator
may contain a cv-qualifier
.
This indicates that your first statement is perfectly valid, since your second init-declarator
*const p = &i;
is a ptr-declarator
of form ptr-operator ptr-declarator
with ptr-operator
being * const
in this case and ptr-declarator
being a unqualified identifier.
Your second statement isn't legal because it is not a valid ptr-operator
:
const c = 2
A ptr-operator
must start with *
, &
, &&
or a nested name specifier followed by *
. Since const c
does not start with either of those tokens, we consider const c
as noptr-declarator
, which does not allow const
here.
Also, why the behaviour differs among 3rd and 4th statements?
Because int
is the type-specifier
, and the *
is part of the init-declarator
,
*const p1
declares a constant pointer.
However, in int const
, we have a decl-specifier-seq
of two decl-specifier
, int
(a simple-type-specifier
) and const
(a cv-qualifier
), see trailing-type-specifier
. Therefore both form one declaration specifier.
* Note: I've omitted all alternatives which cannot be applied here and simplified some rules. Refer to section 7 "Declarations" and section 8 "Declarators" of C++11 (n3337) for more information.