views:

172

answers:

5

I make regular use of forward class declarations and pointers to such classes.

I now have a need to pass a function pointer through a number of layers. I would prefer to include the header that declares my function pointer's prototype only into the module that dereferences a function pointer rather than into each layer that simply passes along that pointer value.

Is this possible?

=====

From the replies I suspect that I have not expressed by question clearly enough. I seek an analog to a forward class declaration. We all agree that I can write:

class foo;

void bar(foo*);

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

Notice that waz knows nothing about class foo other than its name. Perhaps bar will have access to foo's complete description. Perhaps bar will simply pass p further along. Who cares? Only those sites that dereference a foo*. All other sites need only "class foo;".

Similarly I know that I can write:

typedef void foo(int, double);

void bar(foo*);

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

The difference is that now the identifier foo not only is known to denote a function type but further already carries the full signature/prototype. This forces me into one of two unpleasant scenarios:

1) clone the typedef at multiple sites (yuck! fragile!) 2) stick the typedef in a header and include it everywhere that a foo* is mentioned.

Notice the asymetry: in the case of a data object I only needed to provide a complete description of class foo at those points where I want to dereference a foo*; in the case of a function I need to provide the full signature/prototype everywhere I want to mention a foo*.

So is there anyway to remedy this asymmetry?

A: 

Totally possible. You can copy your function prototype wherever you need it, though when I see this done a lot, alarm bells start to go off.

dicroce
+3  A: 

For passing function pointers you only need to know the argument types and the return type:

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

Here, f() is a function that takes a function pointer to a function that takes an int and returns void.

typedefs make that more readable:

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

In general you might want to look at functors or using e.g. Boost.Function and Boost.Bind. That way you can also pass in bound member functions or function objects:

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

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

// ...
X x;
f(boost::bind(&X::f, &x, _1));
Georg Fritzsche
A: 

Sure, e.g.

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

Now you can pass it around

void foo(FOOFUNC f) {
  f(...);
}
Alex
+3  A: 

You can do this using an undefined structure type, at the cost of an extra dereference.

put this in the main header file:

typedef struct FuncStruct *FuncPtr;

This declares struct FuncStruct but does not declare any fields, then it declares a pointer to this struct called FuncPtr. You can pass FuncPtrs around but you can not dereference them.

then in a particular file (or a more specific .h file), you can actually define a struct FuncStruct like this:

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

Then code past this definition can dereference a FuncPtr to get the actual function pointer.

Note this is an extra dereference from just a cast, and it means you'll need to do some memory management of FuncStructs.

Keith Randall
A: 

It is not clear from your question what you are tryng to do.

Firstly, there's no such thing as "prototype" in C++. The concept of "prototype" (function prototype) is specific to C language only.

Secondly, you mention some "function pointer's prototype" in the message body, while the caption talks about "function prototype". This makes it even more confusing. "Function pointer's prototype" makes no sense. There's no such thing as "prototype" for a pointer, even in C, let alone C++.

So, what is it you want to do? If you want to forward-declare a function - just declare it.

If you want to forward-declare a pointer - also just declare it. In order to obtain a declaration (a non-defining declaration) of an object, just declare it with an extern keyword.

AndreyT