そんな型の作り方を覚えるテクニックがあります。まず、ポインタを名前から読み始め、右から左に読みます。
助けなしでそれを宣言する方法は?
配列
T t[5];
は5 T の配列です。T を関数型にするには、戻り値の型を左側に、パラメーターを右側に記述します。
void t[5](void);
void を返し、パラメータを取らない 5 つの関数の配列になります。しかし、関数自体を配列に詰め込むことはできません! それらはオブジェクトではありません。それらへのポインターのみが可能です。
どうですか
void * t[5](void);
return-type を void へのポインターに変更するだけなので、これはまだ間違っています。括弧を使用する必要があります。
void (*t[5])(void);
これは実際に機能します。t は、void を返し、パラメーターを取らない関数への 5 つのポインターの配列です。
すごい!arras へのポインタの配列はどうですか? それはとても似ています。要素タイプは左側に表示され、寸法は右側に表示されます。ここでも、かっこが必要です。そうしないと、配列が整数ポインターの多次元配列になるためです。
int (*t[5])[3];
それでおしまい!3 つの intの配列への 5 つのポインターの配列。
関数はどうですか?
今学んだことは、関数についても当てはまります。パラメーターをとらず、void を返す別の関数へのポインターを返す int を取る関数を宣言しましょう。
void (*f(int))(void);
上記と同じ理由で、再び括弧が必要です。これで、それを呼び出して、返された関数をもう一度呼び出すことができます。
f(10)();
関数へのポインタを返す 関数への別のポインタを返す
これはどうですか?
f(10)(true)(3.4);
? 言い換えれば、int を取り、double を取り void を返す関数へのポインタを返す bool を取る関数へのポインタを返す関数は、どのように見えるでしょうか? 答えは、それらをネストするだけです:
void (*(*f(int))(bool))(double);
あなたは無限にそうすることができます。実際、関数へのポインターと同じように、配列へのポインターを返すこともできます。
int (*(*f(int))(bool))[3];
これはint を取る関数で、関数へのポインタを返します bool を取る関数は、3 つの int の配列へのポインタを返します
constと何の関係があるのですか?
上記で、基本的な型からより複雑な型を構築する方法を説明したconst
ので、それらがどこに属しているかがわかっている場所に配置できます。考慮してください:
T c * c * c ... * c name;
はT
、最後に指すことになる基本的な型です。c
const または not const のいずれかを表します。例えば
int const * const * name;
定数 int への定数ポインターへの型ポインターを持つように name を宣言します。を変更することはできname
ますが、変更することはできません*name
。
int const * const
どちらも**name
タイプではない
int const
これを上記の関数ポインタに適用してみましょう:
void (* const t[5])(void);
これは、実際には配列が定数ポインターを含むことを宣言します。したがって、配列を作成 (および初期化)した後、星の後に が表示されるため、ポインターは const になります。この場合、星の前const
に a を付けることはできないことに注意してください。定数関数へのポインターがないためです。関数を const にすることはできません。意味がないからです。したがって、以下は無効です。const
void (const * t[5])(void);
結論
関数と配列を宣言する C++ と C の方法は、実際には少し混乱します。最初に理解する必要がありますが、理解すれば、それを使用して非常にコンパクトな関数宣言を記述できます。