For example, let's consider the static storage class specifier. Here are a few examples of both valid and ill-formed uses of this storage class specifier:
static int a; // valid
int static b; // valid
static int* c; // valid
int static* d; // valid
int* static e; // ill-formed
static int const* f; // valid
int static const* g; // valid
int const static* h; // valid
int const* static i; // ill-formed
typedef int* pointer;
static pointer j; // valid
pointer static k; // valid
(The declarations marked "valid" were accepted by Visual C++ 2012, g++ 4.7.2, and Clang++ 3.1. The declarations marked "ill-formed" were rejected by all of those compilers.)
This seems odd because the storage class specifier applies to the declared variable. It is the declared variable that is static, not the type of the declared variable. Why are e and i ill-formed, but k is well-formed?
What are the rules that govern valid placement of storage class specifiers? While I've used static in this example, the question applies to all storage class specifiers. Preferably, a complete answer should cite relevant sections of the C++11 language standard and explain them.
In summary, anywhere in the declaration specifier (See section 7.1 in the ISO/IEC 14882-2012), ie before the
*. Qualifiers after the*are associated with the pointer declarator, not the type specifier, andstaticdoesn't make sense within the context of a pointer declarator.Consider the following cases: You can declare a normal int and a pointer to an int in the same declaration list, like this:
this is because the type specifier is
int, then you have two declarations using that type specifierint,a, and a pointer declarator*awhich declares a pointer toint. Now consider:which should look wrong (as they are), and the reason (as defined in sections 7.1 and 8.1) is because C and C++ require that your storage specifiers go with your type specifier, not in your declarator. So now it should be clear that that the following is also wrong, since the above three are also wrong:
Your last example,
are both valid and both equivalent because the
pointertype is defined as a type specifier and you can put your type specifier and storage specifeir in any order. Note that they are both equivalent and would be equivalent to sayingor