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: foo
se 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,
foo
se convierte implícitamente en un puntero a sí mismo y el primero *
se aplica a ese puntero de función, produciendo la función foo
nuevamente.
- 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,
foo
se convierte implícitamente en un puntero a sí mismo; *
se aplica el unario , cediendo foo
nuevamente.
- 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 &&foo
no funciona: &foo
no es una función; Es un puntero de función que es un valor r. Sin embargo, &*&*&*&*&*&*foo
funcionarí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.
&foo
toma la dirección defoo
, lo que da como resultado un puntero de función que apuntafoo
, como cabría esperar.