Hay algunas piezas en esto que permiten que todas estas combinaciones de operadores funcionen de la misma manera.
La razón fundamental por la que todos estos trabajos es que una función (como foo) es implícitamente convertible en un puntero a la función. Por eso void (*p1_foo)() = foo;funciona: foose convierte implícitamente en un puntero a sí mismo y se le asigna ese puntero p1_foo.
El unario &, cuando se aplica a una función, produce un puntero a la función, al igual que produce la dirección de un objeto cuando se aplica a un objeto. Para punteros a funciones ordinarias, siempre es redundante debido a la conversión implícita de función a puntero de función. En cualquier caso, por eso void (*p3_foo)() = &foo;funciona.
El unario *, cuando se aplica a un puntero de función, produce la función apuntada a, al igual que produce el objeto señalado cuando se aplica a un puntero ordinario a un objeto.
Estas reglas se pueden combinar. Considere su penúltimo ejemplo **foo:
- Primero,
foose convierte implícitamente en un puntero a sí mismo y el primero *se aplica a ese puntero de función, produciendo la función foonuevamente.
- Luego, el resultado nuevamente se convierte implícitamente en un puntero a sí mismo y
*se aplica el segundo , obteniendo nuevamente la función foo.
- Luego se convierte implícitamente en un puntero de función nuevamente y se asigna a la variable.
Puede agregar tantos *s como desee, el resultado es siempre el mismo. *Cuantos más , mejor.
También podemos considerar su quinto ejemplo &*foo:
- Primero,
foose convierte implícitamente en un puntero a sí mismo; *se aplica el unario , cediendo foonuevamente.
- Luego,
&se aplica a foo, produciendo un puntero a foo, que se asigna a la variable.
Sin &embargo, solo se puede aplicar a una función, no a una función que se ha convertido en un puntero de función (a menos, por supuesto, que el puntero de función sea una variable, en cuyo caso el resultado es un puntero a puntero) a una función; por ejemplo, podría agregar a su lista void (**pp_foo)() = &p7_foo;).
Por eso &&foono funciona: &foono es una función; Es un puntero de función que es un valor r. Sin embargo, &*&*&*&*&*&*foofuncionaría, como lo haría &******&foo, porque en ambas expresiones &siempre se aplica a una función y no a un puntero de función de valor.
Tenga en cuenta también que no necesita usar el unario *para hacer la llamada a través del puntero de función; ambos (*p1_foo)();y (p1_foo)();tienen el mismo resultado, nuevamente debido a la conversión de puntero de función a función.
&footoma la dirección defoo, lo que da como resultado un puntero de función que apuntafoo, como cabría esperar.