Указатель на параметр функции vs параметр функции?
Я хотел бы понять, в чем разница между двумя объявлениями, f1
и f2
, ниже:
В f1
я объявляю параметр указателем на функцию типа void()
, как отличается объявление f2
от f1
? Являются ли объявления эквивалентными? В main
я могу вызвать оба из них с помощью прототипа void ()
. Я понимаю концепцию передачи по значению/указателю/ссылке, однако это функции и не совсем понимают разницу. Я не могу "изменить" функцию, переданную как параметр в f1
... Спасибо!
PS: пришел к этому вопросу, когда натыкался на известную проблему Most Vexing Parsing:)
#include <iostream>
using namespace std;
void f1(void (*x)())
{
x();
}
void f2(void x())
{
x();
}
void g1()
{
cout << "Invoking f1(g1())" << endl;
}
void g2()
{
cout << "Invoking f2(g2())" << endl;
}
int main()
{
f1(g1);
f2(g2);
}
Компиляция программы и выход
Invoking f1(g1())
Invoking f2(g2())
Ответы
Ответ 1
Они эквивалентны. Вы запутались в неявном преобразовании указателя, которое происходит с аргументами.
Поскольку вы не можете передать функцию в качестве аргумента функции (вы ничего не можете делать с функциями в C, кроме вызова или принятия их адреса), компилятор молча изменяет аргумент в указатель на функцию.
Это то же самое, что и в случае с массивами - вы не можете передавать массивы в качестве аргументов функции, так что всякий раз, когда вы объявляете аргумент функции в виде массива, он молча превращается в указатель.
Ответ 2
В C и С++, если вы объявляете функциональный параметр, чтобы иметь тип функции, его тип будет скорректирован на указатель функции.
C99, §6.7.5.3/8
Объявление параметра как возвращаемого типа функции 'должно быть отрегулировано на' 'указатель на возвращаемый тип функции, как в 6.3.2.1.
С++ 11, §8.3.5/5
... После определяя тип каждого параметра, любой параметр типа "массив T" или "возвращающая функцию T" является скорректированный на "указатель на T" или "указатель на функцию возврата T", соответственно...
Таким образом, в С++, например, мы можем писать типы как f1
, так и f2
как void(void(*)())
.
Ответ 3
Это альтернативный синтаксис для той же самой вещи. В обоих случаях передается указатель функции, но вы можете использовать синтаксис не указателя в списке параметров. Использование имени функции всегда распадается на указатель на функцию (и это может произойти рекурсивно).