それはその場で定義されています。T
次のように、前に出てきたものを次のタイプに運ぶ方法です。
<some stuff> T
<some stuff> reference to T
T
の型の前に来るものは何でもですT D1
。
たとえば、int& (*const * p)[30]
、T
is int
、D
is & (*const * p)[30]
、およびD1
isという宣言があるとします(*const * p)[30]
。の型T D1
は「constへのポインタ 30 intの配列へのポインタ」です。したがって、引用したルールによれば、のタイプp
は「intへの30参照の配列へのポインタへのポインタ」です。
もちろん、この宣言は §3.4.2/5 によって許可されません。
参照への参照、参照の配列、および参照へのポインタがあってはなりません。
派生宣言子型リストであるという非公式の用語は、C 標準の派生型の定義に由来すると思います(C++ の複合型に似ています)。
次のように、オブジェクト、関数、および不完全な型から任意の数の派生型を構築できます。
- 配列型[...]
- 構造タイプ[...]
- ユニオンタイプ[...]
- 関数タイプ[...]
- ポインタ型[...]
コメントへの回答: 型と宣言子の間で混乱しているようです。たとえば、int* p
が宣言子の場合、 の型p
は「int へのポインタ」です。タイプは、これらの英語のような文として表されます。
例 1 :int *(&p)[30]
これは宣言ですT D
(§8.3.1 ポインタ):
D
形式は次のとおりです。
*
attribute-specifier-seq opt cv-qualifier-seq opt D1
はどこD1
ですか(&p)[3]
。つまりT D1
、 「 int (&p)[3]
3 の配列への参照」型を持つ形式int
です (これを再帰的に処理し、次のステップで §8.3.4 配列などを使用します)。の前にあるものはすべてint
、派生宣言子型リストです。p
したがって、元の宣言では、「への 3 つのポインターの配列への参照」という型があると推測できますint
。魔法!
例 2 :float (*(*(&e)[10])())[5]
これは宣言ですT D
(§8.3.4 配列):
T
->float
D
->(*(*(&e)[10])())[5]
D
次の形式です。
D1 [
定数式opt ]
属性指定子 seq opt
はどこD1
ですか(*(*(&e)[10])())
。この手段T D1
は、float (*(*(&e)[10])())
「float へのポインターを返す () の関数への 10 ポインターの配列への参照」という型を持つ形式です (これは、§8.3/6 を適用してから、§8.3.1 ポインターなどを適用して解決します)。の前にあるものはすべてfloat
、派生宣言子型リストです。p
したがって、元の宣言では、「5 float の配列へのポインターを返す () の関数への 10 ポインターの配列への参照」という型があると推測できます。マジック再び!