Il y a quelques pièces à cela qui permettent à toutes ces combinaisons d'opérateurs de fonctionner de la même manière.
La raison fondamentale pour laquelle tous ces travaux sont qu'une fonction (comme foo
) est implicitement convertible en un pointeur vers la fonction. C'est pourquoi void (*p1_foo)() = foo;
works: foo
est implicitement converti en un pointeur sur lui-même et ce pointeur est affecté à p1_foo
.
L'unaire &
, lorsqu'il est appliqué à une fonction, renvoie un pointeur vers la fonction, tout comme il donne l'adresse d'un objet lorsqu'il est appliqué à un objet. Pour les pointeurs vers des fonctions ordinaires, il est toujours redondant en raison de la conversion implicite de pointeur de fonction en fonction. En tout cas, c'est pourquoi ça void (*p3_foo)() = &foo;
marche.
L'unaire *
, lorsqu'il est appliqué à un pointeur de fonction, produit la fonction pointée, tout comme il renvoie l'objet pointé lorsqu'il est appliqué à un pointeur ordinaire sur un objet.
Ces règles peuvent être combinées. Considérez votre avant-dernier exemple **foo
:
- Tout d'abord,
foo
est implicitement converti en un pointeur sur lui-même et le premier *
est appliqué à ce pointeur de fonction, ce qui donne à foo
nouveau la fonction .
- Ensuite, le résultat est à nouveau implicitement converti en un pointeur sur lui-même et le second
*
est appliqué, ce qui donne à nouveau la fonction foo
.
- Il est ensuite implicitement converti à nouveau en un pointeur de fonction et affecté à la variable.
Vous pouvez ajouter autant de *
s que vous le souhaitez, le résultat est toujours le même. Le plus *
s, le plus joyeux.
Nous pouvons également considérer votre cinquième exemple &*foo
:
- Premièrement,
foo
est implicitement converti en un pointeur sur lui-même; l'unaire *
est appliqué, cédant à foo
nouveau.
- Ensuite, le
&
est appliqué à foo
, ce qui donne un pointeur vers foo
, qui est affecté à la variable.
La &
seule peut être appliqué à une fonction bien, et non à une fonction qui a été converti en un pointeur de fonction ( à moins, bien sûr, le pointeur de fonction est une variable, auquel cas le résultat est un pointeur à un pointeur- à une fonction; par exemple, vous pouvez ajouter à votre liste void (**pp_foo)() = &p7_foo;
).
C'est pourquoi &&foo
ne fonctionne pas: &foo
n'est pas une fonction; c'est un pointeur de fonction qui est une valeur r. Cependant, &*&*&*&*&*&*foo
cela fonctionnerait, tout comme &******&foo
, car dans ces deux expressions, le &
est toujours appliqué à une fonction et non à un pointeur de fonction rvalue.
Notez également que vous n'avez pas besoin d'utiliser l'unaire *
pour effectuer l'appel via le pointeur de fonction; les deux (*p1_foo)();
et (p1_foo)();
ont le même résultat, encore une fois à cause de la conversion de pointeur de fonction en fonction.
&foo
prend l'adresse defoo
, ce qui se traduit par un pointeur de fonction pointant versfoo
, comme on pourrait s'y attendre.