boost::bind/function and C function pointers
Apologies if this topic has already been discussed. I have looked around
on various mailing lists, in addition I have tried to make it work with
the current C++ STL standard with std::mem_fun and std::bind1st but with
no success.
The problem is basically to bind a member function pointer with an
instance of its declaring class and to assign the result to an existing
C library function that expects a C style function pointer. This
certainly works for ordinary C functions and static C++ functions,
however fails for bound member function pointers.
Here is what I am trying to achieve:
#include
On Monday 10 February 2003 04:22 pm, Thomas Pollinger wrote:
Apologies if this topic has already been discussed. I have looked around on various mailing lists, in addition I have tried to make it work with the current C++ STL standard with std::mem_fun and std::bind1st but with no success.
The problem is basically to bind a member function pointer with an instance of its declaring class and to assign the result to an existing C library function that expects a C style function pointer. This certainly works for ordinary C functions and static C++ functions, however fails for bound member function pointers.
Here is what I am trying to achieve:
#include
// C function declared in some library struct E; extern void setCallBack(void (*callback_fct)(E*));
class A { public: void init(); void callBack(E *e); .... };
void A::init() {setCallBack(boost::bind(&A::callBack, this));} void A::callBack(E *e) {...}
I tried also using the STL calls, but without success either: ... setCallBack(std::bind1st(std::mem_fun(&A::callBack), this));
Unfortunately, the major problem with function pointers is that you can't send
any extra data with them, so there isn't a good way to package up the A
pointer and send it to setCallback. However, most C callback interfaces also
store a user-defined void* for callback data, which I'm hoping you omitted
for brevity. With such a void*, you can do something like this:
// C function declared in some library
struct E;
extern void setCallBack(void (*callback_fct)(E*), void* data);
typedef boost::function
Unfortunately, the major problem with function pointers is that you can't send any extra data with them, so there isn't a good way to package up the A pointer and send it to setCallback. However, most C callback interfaces also store a user-defined void* for callback data, which I'm hoping you omitted for brevity. With such a void*, you can do something like this:
In this particular case, there was unfortunatelly no additional parameter to pass private data to the C callback registration function.
// C function declared in some library struct E; extern void setCallBack(void (*callback_fct)(E*), void* data);
typedef boost::function
callback; class A{ public: void init(); void callBack(E* e);
private: callback* cb;
// Trampoline function static void do_callback(E* e, void* data) { (*static_cast
(data))(e); } }; void A::init() { cb = new callback(boost::bind(&A::callBack, this, _1)); setCallback(&do_callback, cb); }
Doug
This is a very useful solution that I am likely going to employ if I
have C function pointers that take also private data. Thanks for the
suggestion.
Probably more as a site note (curiosity if you will on a language level):
#include
On Tuesday 11 February 2003 01:41 am, Thomas Pollinger wrote:
Unfortunately, the major problem with function pointers is that you can't send any extra data with them, so there isn't a good way to package up the A pointer and send it to setCallback. However, most C callback interfaces also store a user-defined void* for callback data, which I'm hoping you omitted for brevity. With such a void*, you can do something like this:
In this particular case, there was unfortunatelly no additional parameter to pass private data to the C callback registration function.
Well, there's always:
std::map
Probably more as a site note (curiosity if you will on a language level):
#include
int someFoo(int val) {return val + 5;}
void someMain() { boost::function
bptr = someFoo; int (*cptr)(int) = someFoo; bptr(5); cptr(5); if (bptr == cptr) printf("equal\n"); } The above code snipet does not compile as the types of bptr and cptr are not the same and thus their values cannot be compared although they are identical.
Even if bptr and cptr were both boost::function instances of the same type they would not compare.
I have not followed the C++ Spec evolution closely and am only familar with what appears to be the 98 spec. Are there any plans to uniformize this on the language level? This would allow interfacing C style code with the nice boost function pointers in a much cleaner way.
The limitation is not a language limitation but a library limitation. One cannot compare two boost::function objects because one cannot necessarily compare two arbitrary function objects, and even simpler versions (e.g., requiring that the boost::function targets have the same type) run into trouble. Doug
Probably more as a site note (curiosity if you will on a language level):
#include
int someFoo(int val) {return val + 5;}
void someMain() { boost::function
bptr = someFoo; int (*cptr)(int) = someFoo; bptr(5); cptr(5); if (bptr == cptr) printf("equal\n"); } The above code snipet does not compile as the types of bptr and cptr are not the same and thus their values cannot be compared although they are identical.
Even if bptr and cptr were both boost::function instances of the same type they would not compare.
OK.
I have not followed the C++ Spec evolution closely and am only familar with what appears to be the 98 spec. Are there any plans to uniformize this on the language level? This would allow interfacing C style code with the nice boost function pointers in a much cleaner way.
The limitation is not a language limitation but a library limitation. One cannot compare two boost::function objects because one cannot necessarily compare two arbitrary function objects, and even simpler versions (e.g., requiring that the boost::function targets have the same type) run into trouble.
True for comparison. However a C function pointer and a boost::function pointer with the same signature virtually have the same type. One would expect that a boost::function pointer should be castable to a C style pointer, as you can have std::string return a const char * pointer to its C style string. E.g. from the code snipet example: int (*cptr)(int) = bptr.fct_ptr(); (or some similar member). In the case of a bound function pointer, fct_ptr should arrange to return a pointer pointing to the function's closure, comprising thus the member function pointer plus eventually bound argument(s). The problem certainly is that boost::function is itself a class and you're handling instances of that class. Any access to its instance data has to happen through its members which seems to rule out the possibility of returning a static or C function compatible type with fct_ptr(). That is why I was not sure whether there is something missing in C++ where you can bind a member function to an instance of its declaring class and as a result getting a C-style compatible function pointer. -Thomas
On Wednesday 12 February 2003 12:53 pm, Thomas Pollinger wrote:
The limitation is not a language limitation but a library limitation. One cannot compare two boost::function objects because one cannot necessarily compare two arbitrary function objects, and even simpler versions (e.g., requiring that the boost::function targets have the same type) run into trouble.
True for comparison. However a C function pointer and a boost::function pointer with the same signature virtually have the same type.
I _strongly_ disagree with this. The syntax (and even semantics) may be similar, in that boost::function can do everything that a function pointer can do (except comparisons), but the two are distinct entities.
One would expect that a boost::function pointer should be castable to a C style pointer, as you can have std::string return a const char * pointer to its C style string.
This assumes that boost::function can be implemented with a single function pointer. As you mention below, this doesn't work if the boost::function object references a function object with instance data.
The problem certainly is that boost::function is itself a class and you're handling instances of that class. Any access to its instance data has to happen through its members which seems to rule out the possibility of returning a static or C function compatible type with fct_ptr(). That is why I was not sure whether there is something missing in C++ where you can bind a member function to an instance of its declaring class and as a result getting a C-style compatible function pointer.
Actually, there was a proposal to add this to C++0x by some of the folks at Borland (Borland C++ has closures as an extension). This solves part of the problem, but not all of it. I often use function objects much more complex than a simple closure with boost::function. Here's a snippet from my own code that binds three values and composes function objects. boost::function can store this function object, but no simple closure extension will be able to store it: boost::bind(boost::mem_fn(&Self::allocateStorage), this, boost::bind(&Attribute::type, _1), "", onHeap) Doug
participants (2)
-
Douglas Gregor
-
Thomas Pollinger