21

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?

Dan Nissenbaum
  • 13,558
  • 21
  • 105
  • 181
  • 1
    I don't have a convincing argument, but I interpret _derived-declarator-type_ as referring to a set of English phrases like "pointer to" or "function with no arguments returning" used in the English description of a type. – aschepler Dec 08 '12 at 16:22
  • 1
    I just posted a [question and answer](http://stackoverflow.com/q/13808932/150634) to further clear this up! – Joseph Mansfield Dec 10 '12 at 20:55
  • Fabulous! That's excellent. – Dan Nissenbaum Dec 10 '12 at 21:19

1 Answers1

17

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!

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • Maybe. But it follows the notational convention of a grammatical category (italicized, dashes, "list"), and also the word "derived" is likely to represent something, if at least informally. – Dan Nissenbaum Dec 08 '12 at 16:32
  • @DanNissenbaum Added an edit about the meaning of "derived" in this case. – Joseph Mansfield Dec 08 '12 at 16:40
  • This seems right on the money, thanks. There's one "loose link" for me: Given that, in your example, the type of `T D1` is "pointer to const pointer to array of 30 int", in the next step this type is being decomposed into "*derived-declarator-type-list* T” (with the assumption that the latter `T` represents a different type), but it's not explained HOW to decompose this. It seems to me that another, equally valid decomposition, for example, is: *derived-declarator-type-list* is "pointer to const pointer" and the new `T` is "array of 30 int", resulting in something different. Any thoughts? – Dan Nissenbaum Dec 08 '12 at 16:59
  • 2
    @DanNissenbaum The `T` in "*derived-declarator-type-list* T" is the same as in `T D1`. The `T` in `T D1` is defined in §8.3 as being the *attribute-specifier-seq_opt decl-specifier-seq* part of the declaration. Which, in this example I've given, is just `int`. Basically, the `T` is the part of a declaration that is shared amongst all declarators (e.g. `int x, y, *z`). – Joseph Mansfield Dec 08 '12 at 17:01
  • Ah! That explains my misunderstanding. I had thought the standard was (annoyingly) re-defining `T`, but now it's clear that it is not. This answer now makes perfect sense. Side note: the use of the term "list", when used formally elsewhere to append a category descriptive, is defined to indicate a comma-separated list, which in this case we don't have... It would be nice if a different term were used, rather than "*derived-declarator-type-list*" (not to mention that it would be nice if there were a [note] somewhere about this, since the text looks ODDLY like a formal grammar). Thanks! – Dan Nissenbaum Dec 08 '12 at 17:12
  • Note that in more realistic cases, parentheses apparently need to be ignored in the "*derived-declarator-type-list* T" construction. Consider `int *(&p)[30]`. In this example, it seems that `T` is `int *(`, `D` is `&p)[30]`, and `D1` is `p)[30]`, such that `T D1` would be `int *(p)[30]` (which is well-formed), the type of the latter being "array of 30 pointer to int". In this case, "*derived-declarator-type-list* T" seems to become: " T" or " int *(", which only makes sense if the parentheses are ignored (allowing to be "array of 30" to create a match). – Dan Nissenbaum Dec 10 '12 at 07:16
  • Unfortunately - this answer seems to collapse in the more complex example `float (*(*(&e)[10])())[5]`. Here, "*derived-declarator-type-list* T" becomes " float **" - and there's nothing that can possibly be substituted for "" that results in "array of 10 pointers to functions returning pointers to array of 5 floats". Any suggestions? – Dan Nissenbaum Dec 10 '12 at 07:44
  • @DanNissenbaum Updated my answer! Hope it helps. I haven't had time to check it, but I think it's right. I'll check later. – Joseph Mansfield Dec 10 '12 at 09:02
  • Thanks again for looking into this... It seems to me that this *would* be correct if (using `int *(&p)[30]` as the example) the standard allowed the original expression `T D` with `T` being `int` to decompose into `T * D1` (with `D1` as noted), and subsequently if the standard then stated to reconstruct the final definition of `p` by re-inserting everything between `T` and `D1` (in this case, `*`) into the final definition of `p`. But, it seems, the standard does not allow either: It requires the original to have *exactly* the form `T & D1`, and to reinsert *only* "reference to" in the final. – Dan Nissenbaum Dec 10 '12 at 12:06
  • 1
    @DanNissenbaum I should have put some references in. This is not only looking at the §8.3.2 References, but all the other sections of §8.3. In fact, that example uses §8.3.1 Pointers, which allows `T D` where `D` has the form `* D1`. All of the sections of §8.3 are applied recursively to a declaration to determine the type. – Joseph Mansfield Dec 10 '12 at 12:37
  • Yes, exactly. I chose the example in §8.3.2 because I have similar questions about pretty much all of the places `T D` is decomposed, and decided to choose one specific example for the sake of illustration. I am back to thinking that in the decomposition `T D` -> (some stuff with `D1` in it), followed by "and the type of the identifier in the declaration T D1 is *derived-declarator-type-list* **T**", that `T` is actually being **redefined** in its second usage. In conjunction with understanding that "*derived-declarator-type-list*" is supposed to be English words, it all makes sense... – Dan Nissenbaum Dec 10 '12 at 12:49
  • I retract that. You're almost certainly right about doing this recursively, thanks. As stated in §8.3.0.3, "Thus, a declaration of a particular identifier has the form **T D**. where **T** is of the form *attribute-specifier-seq_opt decl-specifier-seq* and **D** is a declarator. Following is a recursive procedure for determining the type...". I'm working it through now... – Dan Nissenbaum Dec 10 '12 at 13:06
  • My malformed thinking is now, finally, clear. Indeed: `int *(&p)[30]` does *NOT* have the form `T & D1` (with `T` defined in §8.3.0.3, i.e. a *decl-specifier-seq* from §7). Rather, it has the form `T * D1`, so §8.3.1 for pointers MUST be used. §8.3.1 then requires (recursively) a determination of the "type of the identifier" in `T D1`, where the latter here is now `int (&p)[30]` (so §8.3.4 describing arrays must be used, and so on, recursively). Finally in the recursion, the form **will** look like `T & D1`. Each *derived-declarator-type-list* is the result of its associated recursion. Thanks! – Dan Nissenbaum Dec 10 '12 at 13:53
  • Why does "Example 1" first follow §8.3.1 Pointers and not §8.3.4 Arrays? – Andrew McKinlay Aug 27 '16 at 19:32