Ответ 1
Есть несколько частей, которые позволяют всем этим комбинациям операторов работать одинаково.
Основная причина, по которой все эти работы заключаются в том, что функция (например, foo
) неявно конвертируется в указатель на функцию. Вот почему void (*p1_foo)() = foo;
работает: foo
неявно преобразуется в указатель на себя и этот указатель присваивается p1_foo
.
Унарный &
, применяемый к функции, дает указатель на функцию, точно так же, как он дает адрес объекта, когда он применяется к объекту. Для указателей на обычные функции он всегда избыточен из-за неявного преобразования функции-функции-указателя. В любом случае, поэтому void (*p3_foo)() = &foo;
работает.
Унарный *
, применяемый к указателю на функцию, дает функцию, обозначенную нажатием, так же, как он дает объект, указывающий на объект, когда он применяется к обычному указателю на объект.
Эти правила могут быть объединены. Рассмотрим ваш второй, последний пример, **foo
:
- Во-первых,
foo
неявно преобразуется в указатель на себя, а первый*
применяется к этому указателю функции, снова возвращая функциюfoo
. - Затем результат снова неявно преобразуется в указатель на себя, а второй
*
применяется, снова приводя к функцииfoo
. - Затем он неявно преобразуется в указатель функции снова и присваивается переменной.
Вы можете добавить столько *
, сколько хотите, результат всегда один и тот же. Чем больше *
s, тем веселее.
Мы также можем рассмотреть ваш пятый пример, &*foo
:
- Во-первых,
foo
неявно преобразуется в указатель на себя; применяется унитарный*
, снова возвращающийfoo
. - Затем
&
применяется кfoo
, указывая указатель наfoo
, который присваивается переменной.
&
может применяться только к функции, но не к функции, которая была преобразована в указатель функции (если, конечно, указатель функции не является переменной, и в этом случае результатом является указатель- to-a-pointer-to-a-function, например, вы можете добавить в свой список void (**pp_foo)() = &p7_foo;
).
Вот почему &&foo
не работает: &foo
не является функцией; это указатель на функцию, являющийся значением r. Тем не менее, &*&*&*&*&*&*foo
будет работать, как и &******&foo
, потому что в обоих этих выражениях &
всегда применяется к функции, а не к указателю функции rvalue.
Обратите внимание, что вам не нужно использовать унарный *
для вызова через указатель функции; оба (*p1_foo)();
и (p1_foo)();
имеют тот же результат, опять же из-за преобразования функции-функции-указателя.