「黄金律」 (ポインターだけに適用されるわけではありません)を採用すると、自然に直感的に従うことができ、C/C++ で変数を宣言する際の多くの間違いや落とし穴を回避できます。「黄金律」に違反するべきではありません (基本型にconst
伝播する配列の typedef に適用されるようなまれな例外const
と、C++ に付属する参照があります)。
K&R、付録 A、セクション 8.4、宣言子の意味には次のように記載されています。
各宣言子は、宣言子と同じ形式の構造が式に現れると、指定された型とストレージ クラスのオブジェクトを生成するというアサーションと見なされます。
C/C++ で変数を宣言するには、基本型を取得するために変数に適用する必要がある式をよく考える必要があります。
1) 変数名が必要です
2) 次に、変数名に適用された宣言ステートメントから有効な*として式が出てきます
3) 次に、基本型やストレージなどの宣言の残りの情報とプロパティが続きます
ストレージは、たとえば constness とは対照的に、式の結果に常に付与できる特性ではありません。宣言時にのみ意味があります。したがって、ストレージは 2 以外の場所に配置する必要があります。
int * const *pp;
/*valid*/
int * static *pp;
/*invalid, this clearly shows how storage makes no sense for 2 and so breaks */
/*the golden rule. */
/*It's not a piece of information that goes well in the middle of a expression.*/
/*Neither it's a constraint the way const is, it just tells the storage of */
/*what's being declared. */
K&R は、変数を宣言するときに逆推論を使用することを望んでいたと思いますが、それは一般的な習慣ではないことがよくあります。使用すると、複雑な宣言の間違いや困難のほとんどを回避できます。
*valid は厳密な意味ではありません。x[]、x[size、indexing ではありません]、constness などのいくつかのバリエーションが発生するためです。したがって、2 は(宣言の使用法のために)適切にマップされる式であり、「同じフォーム」、変数の使用を反映するものですが、厳密ではありません。
初心者のための黄金律ボーナス
#include <iostream>
int (&f())[3] {
static int m[3] = {1, 2, 3};
return m;
}
int main() {
for(int i = 0; i < sizeof(f()) / sizeof(f()[0]); ++i)
std::cout << f()[i] << std::endl;
return 0;
}
宣言のコンテキストでは&
、アドレスを取得する操作ではなく、何が参照であるかを伝えるだけです。
f()
:関数f
です
&
return : そのreturnは参照です
- reference
[3]
:参照は3 つの要素の配列への参照です
int
array[i] :要素は int です
したがって、3 つの整数の配列への参照を返す関数があり、配列サイズの適切なコンパイル時間情報があるため、sizeof
いつでもチェックできます =)
型の前に配置できるものについては、複数の宣言の場合、すべての変数に一度に適用する必要があるため、個別に適用することはできません。
これconst
は前に置くことはできませんint
:
int * const p;
したがって、以下が有効です。
int * const p1, * const p2;
これは次のことができます:
int const *p; // or const int *p;
したがって、以下は無効です。
int const *p1, const *p2;
交換可能なconst
ものはすべてに適用されます:
int const *p1, *p2; // or const int *p1, *p2;
宣言規約
そのため、私は常に型の前に置くことができないint *a
ものは変数 ( 、int &b
)の近くに置き、前に置くことができるものはすべて( ) の前に置きvolatile int c
ます。
このトピックについては、http://nosubstance.me/post/constant-bikeshedding/でさらに詳しく説明しています。