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: fooest 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,
fooest implicitement converti en un pointeur sur lui-même et le premier *est appliqué à ce pointeur de fonction, ce qui donne à foonouveau 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,
fooest implicitement converti en un pointeur sur lui-même; l'unaire *est appliqué, cédant à foonouveau.
- 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 &&foone fonctionne pas: &foon'est pas une fonction; c'est un pointeur de fonction qui est une valeur r. Cependant, &*&*&*&*&*&*foocela 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.
&fooprend l'adresse defoo, ce qui se traduit par un pointeur de fonction pointant versfoo, comme on pourrait s'y attendre.