You are oversimplifying the structure of C++ declaration (even though the points you make are perfectly logical). Only at the first sight it might seem that C++ declaration consists of type name and a sequence of comma separated entity names, but in reality in C++ (as well as in C) declaration actually consists of type name and sequence of declarators. The full type information for an entity you declare is split between two separate locations and portion of it is actually a part of its declarator. It is just the way it is in C++. In order to better reflect the actual structure of the declaration (as seen by the language), it might be a good idea to format declarations as
int *a, *b;
i.e. explicitly group *
s with the entity names, not with the type name. (But in the end it is a matter of personal preference.)
As for why it is designed that that way in the language, as you ask in one of the comments... As you know, the parts of the declaration syntax that describe the type of the entity being declared can appear on the left-hand side of the name (like *
and &
) as well as on its right-hand side (like ()
and []
) as in
int *f(), (&g)[5], h[2][2];
For the bits that appear on the right it is simply impossible to do it in any other way. They have no choice but to be grouped with the entity name, not with the type name. One might ask further why the above declarations are not done in C++ as
int *() f;
int (&)[5] g;
int [2][2] h;
(i.e. everything type-related appears on the left-hand side in a compact group)... Well, the answer to this question is just that it is the way it is in C++. The approach is inherited from C and there the "declaration must resemble the use" is often quited as the rationale.
P.S. Another thing to remember (and what is often interpreted incorrectly) is that qualifiers adjacent to the type name in the declaration are part of the common type, not a part of the first individual declarator. For example
int const *a, *b;
declares const int *a
and const int *b
, not int *b
as some might mistakingly believe. For this reason I personally prefer to use the more logical
const int *a, *b;
ordering (even though at the same time I prefer to group *
with the name, not with the type).