Question about boost::function

Started by
8 comments, last by Neon2302 16 years, 1 month ago
Dear All, as usaual, pointer to function can cast to void(*)() like int fun1(int b, int c); can cast to void(*ptrToFun)() = fun1; and also boost::function can hold a function even it is a member function like class cla { public : int fun2(int b, int c); }; boost::function<int (int, int)> bo_fun; cla instance; bo_fun = boost::bind(&cla::fun2, &instance, _1, _2); and then we can use bo_fun as pointer to function int i = bo_fun(1, 1); also we can keep fun1 in bo_fun bo_fun = fun1; but then void(*ptrToFun)() = bo_fun; It is illegal ????????????????????? which I prefer to use, since I need to pass member function to other function as void(*)() anyone have an idea or solution for this problem (anythings with or without boost), Thank you Best Regards, Chet Chetchaiyan
Advertisement
void bo_fun_helper() { bo_fun(); }void(*ptrToFun)() = &bo_fun_helper;


Raw function pointers are a PITA because they're completely inflexible. If it's infeasable to write a single function to pass (e.g. because you have multiple bo_fun(s)), please post the context of what function you're being forced to pass a raw function pointer to.
Dear MaulingMonkey,
Thank you for you help, actually I try to write my own library which clover other library. And the one I use for GUI is GTK++. GTK++ use signal mechanism for event. the function(marco) is

g_signal_connect (GtkWidget*, gchar* event_name,
GCALLBACK funtion, gpointer data);

I already check "GCALLBACK" and it's a void(*)()


normally GTK++ provide G_CALLBACK(fun) marco which cast pointer to function to void(*)()

but it's can't work on pointer to member, boost::bind

my point is I want to find the best solution for this case
At this time, I can use static-function and the middle and in the static-function I call member function. But I quite confident that I can eliminate static-function to make my code more encapsulated

the reason I confident is

void(*ptrToFun)​() = fun1;
G_CALLBACK(ptrToFunc); //legal

boost::function<int (int, int)> bo_fun;
bo_fun = boost::bind(&cla::fun2, &instance, _1, _2);
bo_fun = ptrToFun; // also legal

G_CALLBACK(bo_fun); //illegal

which should be have the way back from bo_fun to ptrToFun as it assigned

Best Regards,
Chet Chetchaiyan
The problem is that boost::function needs to store state data about what parameters to pass (including the "this" pointer for member functions), which simply can't fit into a single raw pointer to a function.

For GTK, it looks like the function is required to have a specific signature... in the case of g_signal_connect, a single pointer. The pointer passed is selected with the data parameter of g_signal_connect. This allows us to pass in the missing state data:

namespace mystuff {    namespace details {        void signal_connect_callback( boost::function< void() > * real_callback ) {            (*real_callback)();        }    }    void signal_connect ( GtkWidget* widget, gchar* event, const boost::function< void () > &callback ) {        g_signal_connect( widget, event, G_CALLBACK(&details::signal_connect_callback), &callback );    }}// use mystuff::signal_connect instead of g_signal_connect directly:boost::function< void () > bo_fun = ...;GtkWidget* widget = ...;gchar* event = ...;mystuff::signal_connect( widget, event, bo_fun );


WARNING: This code assumes the passed boost::function< void() > will exist for the entire time that the callback is registered. It is up to you to ensure this happens. A better version might store a copy of the function somewhere and use that. Or you may prefer to be able to change the function and have those changes reflected in the connected signal like currently happens -- it's your call.
I just try your solution, but I got an error


boost::function<gboolean (GtkWidget*, GdkEvent*, gpointer)> bo_fun;
bo_fun = boost::bind(&Window::deleteEvent, window.get(), _1, _2, _3);
mystuff::signal_connect( (GtkWidget*)(window.get()->m_Window).get(), delete_event", bo_fun );


C:\Documents and Settings\User\My Documents\CodeBlocks\NeEngine\src\NeEngine.cpp||In function `void test()':|
C:\Documents and Settings\User\My Documents\CodeBlocks\NeEngine\src\NeEngine.cpp|32|error: invalid initialization of reference of type 'boost::function<void ()(), std::allocator<void> >&' from expression of type 'boost::function<gboolean ()(GtkWidget*, GdkEvent*, void*), std::allocator<void> >'|
C:\Documents and Settings\User\My Documents\CodeBlocks\NeEngine\src\NeEngine.cpp|17|error: in passing argument 3 of `void mystuff::signal_connect(GtkWidget*, gchar*, boost::function<void ()(), std::allocator<void> >&)'|
||=== Build finished: 2 errors, 0 warnings ===|


do you have any idea?
I got it !!!

Thank you very much,

The complete solution is


namespace mystuff {
namespace details {
gboolean signal_connect_callback(GtkWidget *widget, GdkEvent *event, boost::function<gboolean (GtkWidget*, GdkEvent*, gpointer)>* real_callback){
return (*real_callback)(widget, event, NULL);
}
}
void signal_connect ( GtkWidget* widget, gchar* event, boost::function<gboolean (GtkWidget*, GdkEvent*, gpointer)> &callback ) {
g_signal_connect( G_OBJECT(widget), event, G_CALLBACK(&details::signal_connect_callback), &callback );
}
}

boost::function<void ()> bo_fun2;
bo_fun2 = boost::bind(&Window::testBo, window.get());

mystuff::signal_connect( (GtkWidget*)(window.get()->m_Window).get(), "delete_event", bo_fun );
gui.mainLoop();


but in this case, we can't send extra data to the function (since we send boost::function<> on that slot)

any idea??

any ways, I really thankful to your help this is just not for this project but also improving my programming skill.

Thank you and Best Regards,
Chet Chetchaiyan
RAIIified.

namespace bleh {    class signal : boost::noncopyable {        gulong handler;        boost::function< void() > f;        static void f_caller( const signal* self ) { self->f(); }    public:        signal( GtkWidget* widget, gchar* event ) {            handler = g_signal_connect( widget, event, G_CALLBACK(&f_caller), this );        }        signal( GtkWidget* widget, gchar* event, const boost::function< void() >& f ): f(f) {            handler = g_signal_connect( widget, event, G_CALLBACK(&f_caller), this );        }        signal& operator=( const boost::function< void() > & f ) {            this->f = f;            return this;        }        ~signal() {            g_signal_disconnect( widget, handler );        }    };}
Quote:Original post by Neon2302
but in this case, we can't send extra data to the function (since we send boost::function<> on that slot)

any idea??


You can send any extra data you want by using boost::bind. You'll have to store the result in a function that stays alive the entire time the signal is, though. Blame it's C style API :).

Quote:any ways, I really thankful to your help this is just not for this project but also improving my programming skill.


No problem.
C:\Documents and Settings\User\My Documents\CodeBlocks\NeEngine\src\NeEngine.cpp|28|error: invalid initialization of non-const reference of type 'bleh::signal&' from a temporary of type 'bleh::signal* const'|

I got this error from your code, any idea?
Work now \^_^/

you code is almost perfect (from my knowhow)

so now I have the signal class which can carry data and register/unregister by itself

I have less (really less) background in advance C
I try to use boost library as my starting point but most of them is still too hard to understand (such as bind, and a lot more, or you can call almost of them T_T)

do you have any suggestion for finding the reading article such as web/book/journal/code with comment/etc...

Thank you again
Chet Chetchaiyan

This topic is closed to new replies.

Advertisement