これには、これらの演算子のすべての組み合わせが同じように機能するためのいくつかの要素があります。
これらすべてが機能する根本的な理由は、関数(などfoo
)が関数へのポインターに暗黙的に変換可能であることです。これが機能する理由void (*p1_foo)() = foo;
です。 foo
は暗黙的にそれ自体へのポインタに変換され、そのポインタがに割り当てられp1_foo
ます。
unary &
は、関数に適用されると、オブジェクトに適用されたときにオブジェクトのアドレスを生成するのと同じように、関数へのポインターを生成します。通常の関数へのポインターの場合、関数から関数へのポインターの暗黙的な変換のため、これは常に冗長です。いずれにせよ、これが機能する理由void (*p3_foo)() = &foo;
です。
単項を*
関数ポインタに適用すると、オブジェクトへの通常のポインタに適用されたときに、ポイントされたオブジェクトが生成されるのと同じように、ポイントされた関数が生成されます。
これらのルールは組み合わせることができます。最後から2番目の例を考えてみます**foo
。
- 1つ目
foo
は暗黙的にそれ自体へのポインターに変換され、1つ目*
はその関数ポインターに適用され、関数がfoo
再び生成されます。
- 次に、結果は再び暗黙的にそれ自体へのポインターに変換され、2番目
*
が適用されて、再び関数が生成されますfoo
。
- 次に、暗黙的に再度関数ポインターに変換され、変数に割り当てられます。
はいくつでも追加でき*
ます。結果は常に同じです。*
sが多ければ多いほど、楽しいものになります。
5番目の例も考えられます&*foo
。
- まず、
foo
暗黙的にそれ自体へのポインタに変換されます。単項*
が適用され、foo
再び降伏します。
- 次に、
&
がに適用され、変数に割り当てられているへのfoo
ポインタが生成foo
されます。
&
のみならず、その結果、ポインタツーpointer-である場合には、当然のことながら、関数ポインタが可変である、ない限り、関数ポインタ(に変換された関数に、ものの関数に適用することができますto-a-function;たとえば、リストに追加できますvoid (**pp_foo)() = &p7_foo;
)。
これが機能&&foo
しない理由です: &foo
は関数ではありません。これは、右辺値である関数ポインターです。しかし、&*&*&*&*&*&*foo
同じように、仕事と&******&foo
それらの式の両方であるため、&
常に関数にしていない右辺値関数ポインタに適用されます。
また*
、関数ポインタを介して呼び出すために単項を使用する必要がないことにも注意してください。両方(*p1_foo)();
と(p1_foo)();
なぜなら関数に関数ポインタ変換再度、同一の結果を有します。
&foo
のアドレスを受け取りますfoo
。これにより、関数ポインタがを指すfoo
ようになります。