In the standard, what is “derived-declarator-type”

2019-01-17 08:47发布

问题:

In different places in the C++ (C++11) standard, declarations are described in terms of derived-declarator-type-list. I am studying rvalue references and the use of this term is critical in that context (§8.3.2):

In a declaration T D where D has either of the forms
    & attribute-specifier-seqopt D1
    && attribute-specifier-seqopt D1
and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T,” then the type of the identifier of D is “derived-declarator-type-list reference to T.”

Unfortunately, the category "derived-declarator-type" is never defined in the standard. (I looked through every use of the word "derived", and in addition this is possibly confirmed here and here.)

Because "derived-declarator-type-list" is italicized, I assume it refers to a category, and not to a variable label such as T (and therefore, I disagree with Doug Gwyn's assessment in the second link I just gave that "we could have used X instead of 'derived-declarator-type-list' ").

What is the definition of derived-declarator-type in the C++11 standard?

回答1:

It's being defined right there and then. It's a way of carrying whatever comes before T across to the next type, similar to:

<some stuff> T
<some stuff> reference to T

It's just whatever comes before T in the type of T D1.

For example, if you have the declaration int& (*const * p)[30], T is int, D is & (*const * p)[30] and D1 is (*const * p)[30]. The type of T D1 is "pointer to const pointer to array of 30 int". And so, according to the rule you quoted, the type of p is "pointer to const pointer to array of 30 reference to int".

Of course, this declaration is then disallowed by §3.4.2/5:

There shall be no references to references, no arrays of references, and no pointers to references.

I think the informal terminology of it being a derived declarator type list comes from the C standard's definition of a derived type (similar to a compound type in C++):

Any number of derived types can be constructed from the object, function, and incomplete types, as follows:

  • An array type [...]
  • An structure type [...]
  • An union type [...]
  • An function type [...]
  • An pointer type [...]

In response to the comments: It seems you're getting confused between the type and the declarator. For example, if int* p is the declarator, then the type of p is "pointer to int". The type is expressed as these English-like sentences.

Example 1: int *(&p)[30]

This is a declaration T D where (§8.3.1 Pointers):

  • T -> int
  • D -> *(&p)[3]

D has the form:

* attribute-specifier-seqopt cv-qualifier-seqopt D1

where D1 is (&p)[3]. That means T D1 is of the form int (&p)[3] which has type "reference to array of 3 int" (you work this out recursively, next step using §8.3.4 Arrays and so on). Everything before the int is the derived-declarator-type-list. So we can infer that p in our original declaration has type "reference to array of 3 pointer to int". Magic!

Example 2: float (*(*(&e)[10])())[5]

This is a declaration T D where (§8.3.4 Arrays):

  • T -> float
  • D -> (*(*(&e)[10])())[5]

D is of the form:

D1 [ constant-expressionopt ] attribute-specifier-seqopt

where D1 is (*(*(&e)[10])()). This means T D1 is of the form float (*(*(&e)[10])()) which has type "reference to array of 10 pointer to function of () returning pointer to float" (which you work out by applying §8.3/6 and then §8.3.1 Pointers and so on). Everything before the float is the derived-declarator-type-list. So we can infer that p in our original declaration has type "reference to array of 10 pointer to function of () returning pointer to array of 5 float". Magic again!