Question about boost::function
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
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
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:
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.
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?
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
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?
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
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
Popular Topics
Advertisement