2010-04-04 2 views
7

Я регулярно применяю декларации и указатели вперед к таким классам.Любой способ в C++ переслать объявление прототипа функции?

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

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

=====

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

класс foo;

void bar (foo *);

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

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

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

ЬурейеГо ничтожной Foo (INT, двойной);

void bar (foo *);

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

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

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

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

Итак, есть ли способ устранить эту асимметрию?

+0

Нет асимметрии. Вы можете переслать объявление класса и функции, а не typedef. Typedef - это просто псевдоним, он больше не существует во время соединения, поэтому нет ничего, чтобы переслать объявление об этом. –

+0

Ваш аргумент ошибочен. Да, при использовании функция должна существовать во время соединения или вы получаете неопределенную ошибку символа. OTOH, объявленный вперед класс не имеет. Экземпляры такого класса могут существовать, но они не являются тем, что обозначено форвардным объявленным именем класса. Переадресованное объявленное имя класса обозначает класс, а не объект, занимающий хранилище. –

+0

"_A forward объявленное имя класса обозначает ** [тип] **, а не объект, занимающий хранилище.« Точно так же, как указатель функции обозначает ** тип **, а не функцию, занимающую инструкции (и точку входа) в программа. Я хочу сказать, что речь идет не о 'typedef'; это не имеет значения. –

ответ

-1

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

3

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

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

Уверенный, например.

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

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

void foo(FOOFUNC f) { 
    f(...); 
} 
+0

Как это форвардное объявление? Это простой typedef, не так ли? – Zoso

4

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

положить это в основном файле заголовка:

typedef struct FuncStruct *FuncPtr; 

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

затем в определенном файле (или более конкретного файла .h), вы можете определить struct FuncStruct вроде этого:

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

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

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

-1

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

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

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

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

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

0

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

/* 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 B.h` (что, вероятно, даже не работает)?

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

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

+1

Вы можете использовать любой указатель на функцию вместо фактического указателя функции, таких как 'void (*)()'. Стандарт гарантирует, что указатели на функции любого типа могут быть конвертированы в любой другой тип. – BeeOnRope

Смежные вопросы