Bind member function Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Bind member function

Post by priyank_bolia » Thu Jul 10, 2008 5:09 pm

I have to pass my member function instead of regular function name to the GTK+ function, how to do that:


lets say:

Code: Select all

gboolean checkTimer(gpointer data)
{
    g_timeout_add(500, checkTimer, NULL);
}
to something of say class X member function.

Code: Select all

class X
{
    gboolean checkTimer(gpointer data)
    {
	g_timeout_add(500, checkTimer, NULL);
    }
}

mc2r
wxWorld Domination!
wxWorld Domination!
Posts: 1195
Joined: Thu Feb 22, 2007 4:47 pm
Location: Denver, Co
Contact:

Post by mc2r » Thu Jul 10, 2008 5:13 pm

I am not sure I understood what you are looking for but I think it might be this.

Code: Select all

::checkTimer(someData); // This will call regular function
X::checkTimer(someData); // This will call member function only valid from within another member function or outside if member function is static.
someX_ptr->checkTimer(someData); // This will call the member function of pointer to a specific instance of X
someX_ptr.checkTimer(someData); // This will call the member function of a specific instance of X
Hope this helps,

-Max

priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia » Thu Jul 10, 2008 5:18 pm

The g_timeout_add will take the function name to be called on timeout.
Not instead of a normal free function, I want to call the member function of some class.
X a;
a.SomeFunction();


instead of SomeFreeFunction();

I want to know how to pass the member function name, and bind it to an class object and pass it to g_timeout_add
Thanks,
Priyank

priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia » Thu Jul 10, 2008 5:23 pm

Code: Select all

class X
{
    gboolean checkTimer(gpointer data)
    {
	boost::function<gboolean (gpointer)> f = std::bind1st(std::mem_fun(&X::checkTimer), this);
	g_timeout_add(500, f, NULL);
    }
}
I am trying to do this, but getting error:
cannot convert ‘boost::function<gboolean ()(void*), std::allocator<void> >’ to ‘gboolean (*)(void*)’ for argument ‘2’ to ‘guint g_timeout_add(guint, gboolean (*)(void*), void*)’

mc2r
wxWorld Domination!
wxWorld Domination!
Posts: 1195
Joined: Thu Feb 22, 2007 4:47 pm
Location: Denver, Co
Contact:

Post by mc2r » Thu Jul 10, 2008 5:34 pm

priyank_bolia wrote:The g_timeout_add will take the function name to be called on timeout.
Not instead of a normal free function, I want to call the member function of some class.
X a;
a.SomeFunction();


instead of SomeFreeFunction();

I want to know how to pass the member function name, and bind it to an class object and pass it to g_timeout_add
Thanks,
Priyank
Ok, I understand. You will need to make a callback function that does this for you.

Code: Select all

g_timeout_add(500, ClassCallback, data); // Where data is a pointer to your class instance

ClassCallback(gpointer data){
    X x* = dynamic_cast<X*>(data);
    if(x)
        x->SomeFreeFunction();
}
I am not sure what gpointer is defined as you will have to look at the docs to figure this out. You have to add the extra function for hanlding callbacks in a class because class member functions have a hidden argument that gets passed for the this*.

-Max

priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia » Thu Jul 10, 2008 5:39 pm

It is not necessary that the data will be a pointer only, for different GTK function take different params.
Like it can be timer ID, etc.

Also I don't want to define another wrapper function for call delegation, the code doesn't looks good. Also my class has no virtual method for dynamic cast to work.

Can this be done using Boost::Bind, Boost::Function and bind1st, etc. in a single line.

mc2r
wxWorld Domination!
wxWorld Domination!
Posts: 1195
Joined: Thu Feb 22, 2007 4:47 pm
Location: Denver, Co
Contact:

Post by mc2r » Thu Jul 10, 2008 5:49 pm

priyank_bolia wrote:Also I don't want to define another wrapper function for call delegation, the code doesn't looks good.
This is the only way I know of it make it work. A class member function can not be called as part of a call back this way as the member function needs an extra argument passed to it for the

Code: Select all

this
pointer.

And it doesn't really matter if your code looks good if it doesn't work. Besides, does having an extra 4-5 line function for call delegation really make your code look worse than say jamming all of this
priyank_bolia wrote:Can this be done using Boost::Bind, Boost::Function and bind1st, etc. in a single line.
on one line? I don't think so, maybe you have a different idea of what good code looks like.

As for using Boost::Bind, et al I don't know at all I've never used them, I've always done call delegation the way i described. Maybe some one else would know.

Also, this whole thread is kind of off topic for this forum as it is all gtk code and not really wxWidgets related. Maybe you will find someone more knowledgable in a more appropriate forum.

-Max

eranif
Moderator
Moderator
Posts: 607
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Post by eranif » Thu Jul 10, 2008 8:03 pm

If i understand what you want to do, is to pass X::callback to the timer and not any global function.

AFAIK, You cant.

The best solution is this:

Code: Select all

class X {
	gboolean callback(gpointer data) {
		X *ctx = (X*)data;
		// ctx is now this
		
		// add another call to the timer
		g_timeout_add(500, callback, this);		
	}
};

Eran
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org

priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia » Thu Jul 10, 2008 8:20 pm

To mc2r:
And it doesn't really matter if your code looks good if it doesn't work. Besides, does having an extra 4-5 line function for call delegation really make your code look worse than say jamming all of this
Well, this is what I am doing, the another solution is to use static member function. But I am open to better solutions.
As for using Boost::Bind, et al I don't know at all I've never used them, I've always done call delegation the way i described. Maybe some one else would know.
I am also new to Boost, so learning to solve problems using it. Its gr8 library.
Also, this whole thread is kind of off topic for this forum as it is all gtk code and not really wxWidgets related. Maybe you will find someone more knowledgable in a more appropriate forum.
Well the code is wxWidget only, but there are some features missing in wxWidgets, so writing a wrapper on top of GTK. Also with so many C++/Cross Platform developers here, I think this is the best forum I know.



To Eran:
You added callback as member of class X, which is the actual problem and not the solution :), as the g_timeout_add takes a free function signature and not a member function.
I guess you wanted to say what mc2r has said.

Frank
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 211
Joined: Sat Jan 01, 2005 6:19 pm

Post by Frank » Thu Jul 10, 2008 11:03 pm

It's not a Problem with boost::bind() (wich is BTW part of C++09, the draft will be ready in September).

This should work:

Code: Select all

class X
{
    gboolean checkTimer(gpointer data)
    {
        g_timeout_add(500, checkTimer, NULL);
    }
}

X a;

boost::function<gboolean(gpointer)> func = boost::bind(&X:checkTimer, &a, _1);

// func can now be used, like a function:
gboolean rc = func(myData);
Of course, boost::function<> is no real function, it's just another functor. So if the GTK-Function takes a functor as callbak, you could simple implement your checkTimer() function as oparator() and, voila, you have a functor.

See, it's a single line ;-)

priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia » Fri Jul 11, 2008 4:45 am

@Frank:
if you check the above code, its the same thing thing as bind. The problem is g_timeout_add is not taking a reference to the callback, its plainly taking the name.
So boost::bind or std::bind1st, etc. won't work.
This is the actual problem, how to get them work for functions taking name of other functions, instead of function pointer.

eranif
Moderator
Moderator
Posts: 607
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Post by eranif » Fri Jul 11, 2008 5:56 am

@pryiank_bolia:

I forgot to mark the function as static.

You can pass callback only if the function is static. The idea is to past the 'this' as the argument to provide context to static function.

The correct code, that should work:

Code: Select all

class X {
        void doSomething() {
			// code
			
			// now add callback
			g_timeout_add(500, callback, this);
        }
		
        static gboolean callback(gpointer data) {
                X *ctx = (X*)data;
                // ctx is now the context 
               
                // if u need another timeout, 
				// just add it here and pass ctx as data
                g_timeout_add(500, callback, ctx);          
        }
};

Eran
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org

priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia » Fri Jul 11, 2008 6:06 am

@Eranif:
Yes the callback wrapper method works (whether static or non static), as we already talked above. But it doesn't look to me clean solution, what if some API don't take "this" pointer, then you will need global data, and what will happen when there are multiple callbacks.

eranif
Moderator
Moderator
Posts: 607
Joined: Tue Nov 29, 2005 7:10 pm
Location: Israel

Post by eranif » Fri Jul 11, 2008 6:12 am

there is no problem with multiple callbacks, since you are handling the timeout inside the context.

something like this:

Code: Select all

ctx->OnTimeout();
So this is a perfectly thread-safe function (I assume this is what you meant by multiple calls)

Eran
IDE: CodeLite + wxCrafter
OS: All
https://wxcrafter.codelite.org
https://codelite.org

priyank_bolia
wxWorld Domination!
wxWorld Domination!
Posts: 1339
Joined: Wed Aug 03, 2005 8:10 am
Location: BANGALORE, INDIA
Contact:

Post by priyank_bolia » Fri Jul 11, 2008 6:38 am

Sorry I was talking about when you don't have "this" pointer, the callback don't take any parameter or some other params like ID.
Then if you use global variable to store "this" .....

Post Reply