Любой способ в C ++ для вперед объявить прототип функции? - PullRequest
8 голосов
/ 04 апреля 2010

Я регулярно использую объявления классов вперед и указатели на такие классы.

Теперь мне нужно пропустить указатель на функцию через несколько слоев. Я бы предпочел включить заголовок, который объявляет прототип моего указателя функции только в модуль, который разыменовывает указатель на функцию, а не в каждый слой, который просто передает значение этого указателя.

Возможно ли это?

=====

Из ответов я подозреваю, что недостаточно четко сформулировал вопрос. Я ищу аналог для объявления класса forward. Мы все согласны, что я могу написать:

class foo;

пустая строка (foo *);

void waz (foo * p) {bar (p); }

Обратите внимание, что waz ничего не знает о классе foo, кроме его имени. Возможно, у бара будет доступ к полному описанию foo. Возможно, бар просто пройдет дальше. Какая разница? Только те сайты, которые разыменовывают foo *. Всем остальным сайтам нужен только «класс foo;».

Точно так же я знаю, что могу написать:

typedef void foo (int, double);

пустая строка (foo *);

void waz (foo * p) {bar (p); }

Разница в том, что теперь идентификатор foo не только известен как обозначающий тип функции, но также уже содержит полную сигнатуру / прототип. Это приводит меня к одному из двух неприятных сценариев:

1) клонировать typedef на нескольких сайтах (хм! Хрупкий!) 2) вставьте typedef в заголовок и включайте его везде, где упоминается foo *.

Обратите внимание на асимметрию: в случае объекта данных мне нужно было предоставить полное описание класса foo только в тех местах, где я хочу разыменовать foo *; в случае функции мне нужно предоставить полную сигнатуру / прототип везде, где я хочу упомянуть foo *.

Так есть ли способ исправить эту асимметрию?

Ответы [ 6 ]

4 голосов
/ 04 апреля 2010

Вы можете сделать это, используя неопределенный тип структуры, за счет дополнительной разыменования.

поместите это в основной заголовочный файл:

typedef struct FuncStruct *FuncPtr;

Это объявляет struct FuncStruct, но не объявляет никаких полей, затем оно объявляет указатель на эту структуру с именем FuncPtr. Вы можете передавать FuncPtr с, но вы не можете разыменовать их.

затем в конкретном файле (или более конкретном файле .h) вы можете определить struct FuncStruct следующим образом:

struct FuncStruct {
  int (*f)(int, char, double);
};

Тогда код после этого определения может разыменовать FuncPtr для получения фактического указателя на функцию.

Обратите внимание, что это дополнительная разыменование от просто приведения, и это означает, что вам необходимо выполнить некоторое управление памятью FuncStruct с.

3 голосов
/ 04 апреля 2010

Для передачи указателей на функции вам нужно знать только типы аргументов и тип возвращаемого значения:

void f(void (*func)(int));

Здесь f() - это функция, которая берет указатель на функцию, которая принимает int и возвращает void.

typedef s делают это более читабельным:

typedef void (*FuncPtr)(int);
void f(FuncPtr func);

Как правило, вы можете посмотреть на функторы или использовать, например, Boost.Function и Boost.Bind . Таким образом, вы также можете передать связанные функции-члены или функциональные объекты:

void f(boost::function<void (int)> fn) {
    fn(42);
}

struct X {
    void f(int) {}
};

// ...
X x;
f(boost::bind(&X::f, &x, _1));
0 голосов
/ 19 мая 2017

Я точно понимаю, что пытается сделать ОП.На самом деле, я хочу сделать то же самое.Исходя из сказанного ОП, у меня есть следующее (на С, а не на С ++):

/* File A.h */
typedef void (*f_t)(int x);

/* File B.h */
typedef void (*call_f_t)(f_t func2call,int y);

Вопрос в том, должен ли B.h включать A.h?A.h определяет все виды других вещей, которые я бы предпочел не включать в B.h', so I am hoping is a way to "forward reference" a function pointer, without redefining it in a typedef in Bh` (что, вероятно, даже не работает)?

Или компилятору нужно знать больше о f_t в B.h, чем о, скажем, форварде, на который ссылается struct?

Также возможно, что мне нужно переосмыслить компоновку моего кода, но я согласен с ФП, что в идеальном мире должна быть какая-то симметрия между указателями функций и другими объектами, которые могут бытьвперед ссылки.

0 голосов
/ 04 апреля 2010

Из вашего вопроса не ясно, что вы пытаетесь сделать.

Во-первых, в C ++ нет такого понятия, как "прототип".Понятие «прототип» (функция prototype) относится только к языку C.

Во-вторых, вы упоминаете о некотором «прототипе указателя функции» в теле сообщения, в то время как в заголовке говорится о «прототипе функции».Это делает это еще более запутанным.«Прототип указателя функции» не имеет смысла.Нет такого понятия, как «прототип» для указателя, даже в C, не говоря уже о C ++.

Итак, что вы хотите сделать?Если вы хотите объявить функцию вперед - просто объявите ее.

Если вы хотите объявить указатель вперед - просто объявите его.Чтобы получить объявление (не определяющее объявление) объекта, просто объявите его с ключевым словом extern.

0 голосов
/ 04 апреля 2010

Конечно, например,

typedef void (*FOOFUNC)(int x, int y, char z);

Теперь вы можете передать его

void foo(FOOFUNC f) {
  f(...);
}
0 голосов
/ 04 апреля 2010

Вполне возможно. Вы можете скопировать прототип своей функции, где бы он вам ни понадобился, хотя, когда я вижу, что это уже сделано, тревожные сигналы начинают срабатывать.

...