I would need a member function to be passed into a third party external method:
box_self_intersection_d(mycallback);
The box_self_intersection_d is a third party external static method, and I cannot modify it. mycallback is a method I want to pass it into the box_self_intersection_d, it is a class function and is accessing some members in this class ( have full control for this class and the mycallback)
Is there anyway I can use class member functions as callbacks without declaring them as static functions?
Edit: the signature of mycallback is (const box &boxA, const box &boxB), where box is a special class from the third party provider.
And the signature for box_self_intersection_d is
void box_self_intersection_d(RandomAccessIterator begin,RandomAccessIterator end,Callback callback)
If the function box_self_intersection_d takes a functional as parameters, and mycallback is a method of a class MyClass, you can use boost::bind:
box_self_intersection_d( boost::bind( &MyClass::mycallback, myClassInstance ) );
where myClassInstance is the instance of the class MyClass.
If the callback accepts a void* for user-defined data, you can use a static wrapper function that casts the void* argument to the class type and calls your member function.
Example:
static void Foo::callback_method(void* data) {
static_cast<Foo*>(data)->mycallback();
}
void Foo::register_my_callback() {
box_self_intersection_d(&Foo::callback_method, this);
}
Most sane callback libraries allow you to pass this void* argument to the functions as a way to have user-defined data in it. If not, you'll need to resort to the dirty method:
static Foo* Foo::callback_object;
static void Foo::callback_method() {
callback_object->mycallback();
}
void Foo::register_my_callback() {
callback_object = this;
box_self_intersection_d(&Foo::callback_method);
}
In general, if you need to pass a function, there is just no other way: Either you have a data side-channel like the void*, which your library provider seems to have omitted (and is clearly a bug in the library), or you need to transport the this pointer via a global variable.
There are a couple of possible workarounds. You can have a look here: http://www.newty.de/fpt/callback.html#member
In short, you can either:
declare a static "wrapper method" and pass the instance of the class to it,
or else store a pointer to the object as a global variable.
Hope that helps,
You haven't provided the signature box_self_intersection_d()
in general, if the signature is
void box_self_intersection_d( void *cb );
or even
void box_self_intersection_d( void (*cb)(const box&, const box&) );
then you cannot pass it a pointer to a member function.
The reason is that sizeof(a_member_function) is different than
sizeof(a_function_pointer). If this is the case, I think you are forced to use thiton's solution, and create a static function.
Since it's CGAL, the callback is actually a template parameter.
Its only constraints are "Callback must be of the BinaryFunction concept".
That is, it can be anything that is "callable" with the proper parameters.
This includes any object with a void operator() (const box&, const box&) member function.
Implementing that function in your class and passing *this for the callback would probably be the simplest solution.
There is a horrible solution that I can conceive of that means copying/pushing 'this' and function code to the calling stack, (or some other caller-allocated segment that can be made writeable and executable), and passing the address of the function to the library. The called-back function could then find its own code address, extract 'this' using an offset/pointer arith. and call a member function. Should work for multiple threads.
I hereby claim this years 'Gruesome Hack' award for a solution that makes developers feel physically ill but might still actually work if a project manager is pointing a shotgun at your head.
Rgds,
Martin
Related
So I got myself onto shaky ground by insisting on making a C++ class immitate a regular function. The class overloads the function operator, making it a functor, of course. This all works fine, until you want to pass the function pointer of this functor.
Naturally, I want to let the compiler know that we know what we're doing (lol), by doing a reinterpret_cast of this pointer. However, how do I get the address of this particular member function, since it is an overloaded operator. How does one get the address of that?
UPDATE: You asked for an example. Here is a minimal one.
So I have an interface, which I cannot change. It looks like this;
typedef void (*some_callback_t)(SomeType);'
void someFunc(some_callback_t);
Now, this is quite straight-forward; the API is setting some callback function pointer. So, the idea was to implement the callback as a functor class, by overloading the operator(), like so, as usual.
class Bah {
void operator()(SomeType);
};
Here comes the question; seeing as I cannot change the API used (the function that expects a function pointer of a certain signature), how can I then get the address of the member function and pass that?
I suspect it goes something like;
someFunc(reinterpet_cast<some_callback_t>( ? ? ? )); to make sure that the compiler won't barf at me.
Supposing that you have to use a function pointer, and that your functor has no state, you can use a lambda as glue:
void takesFunctionPointer(void (*)());
struct MyFunctor {
void operator()();
};
// ...
takesFunctionPointer([] { return MyFunctor{}(); });
How does one get the address of that?
In the same way as any other member function. The name of the function is class_name::operator(). An example:
struct class_name {
void operator()(){}
};
void (class_name::*member_function_pointer)() = &class_name::operator();
class_name instance;
(instance.*member_function_pointer)(); // in a block scope
Naturally, I want to let the compiler know that we know what we're doing (lol), by doing a reinterpret_cast of this pointer.
That's usually not what one would want to do.
So I have this function:
void EventDispatcher::Subscribe(string eventName, void (*callback)(void *))
{
....
}
I am trying to pass class member function as a callback parameter there.
typedef void (*method)(void*);
void EventTester::RunTests()
{
_dispatcher = new EventDispatcher();
Event eventOne("one");
_dispatcher->Register("one", eventOne);
method p = &onOne;
_dispatcher->Subscribe("one", p);
}
void EventTester::onOne(void *args)
{
std::cout<<"Event one\n";
}
obviously this doesn't compile because onOne is not static and a member function. Is there any way of making it work this way?
You could use boost in C++03 or std::bind and std::function in C++11:
typedef boost::function<void(void*)> func_type;
void EventDispatcher::Subscribe(const string& eventName, const func_type& func_)
{
if ( ! func_.empty() ) {
// you could call the function
func_(NULL);
}
}
//Register looks like in a member function of EventTester:
...
_dispatcher->Subscribe("one",boost::bind(&EventTester::onOne,this,_1));
...
I'm going off the assumption that you have the ability to modify the signature of Subscribe. If not, my answer may not apply.
As you already noted, your pointer-to-member (aka method) is not the same as a plain function pointer. To use a pointer-to-member, you have to supply the class instance to call the function on as part of the method execution.
You could modify Subscribe to explicitly take in a pointer-to-member, which would expect an additional argument (the class instance). You would need Subscribe to store both the function pointer, and a pointer to your object instance. This would then require that all callbacks be implemented as pointers-to-members.
The preferred way to solve this problem is to use bind (either std::bind or boost::bind).
You would need to change your Subscribe function to take in a std/boost::function object instead of an explicit function pointer. This would permit callers of the Subscribe method to pass in any callable object (See the examples in the documentation of std::function)
You can then use bind to connect your class instance to your method pointer. This will return a functor object which will do the work of holding both your pointer-to-member and a pointer to your class instance.
For an example of how to use bind, see this link
Sorry to ask such a question as I'm sure it's been answered before, but I'm struggling to find an answer and it's not for the want of looking... anyway..
class foo
{
void read(void (*func)(obj&))
{
// many things happen to obj...
(*func)(obj); // Calls the function pointer to the handler.
}
};
class bar : public foo
{
void handler(obj&)
{
//
}
};
void main()
{
foo f;
typedef void (foo::*funcptr)(obj&);
funcptr ptr = &foo::handler;
f.read(ptr); ????
}
So basically, all I'm trying to do is pass the non-static member method called handler as a function pointer to the read method, so that when the callback is executed, the handler is called.
I've tried all sorts of ways to make this work and don't want to make static methods (for reasons I won't go into). I think I'm pretty close, but have sort of fallen over right at the end! Any help would be appreciated.
You cannot do that: unlike static functions that can be called on their own, the call of a member function requires knowledge of two things - the function being called, and the object on which to call it. That is why it is not possible to pass a member function to an API expecting a "plain" function pointer.
If you do not have access to the source of the foo class, you can create a static function that calls a member function on an object stored at a well-known location (i.e. in a static variable). If you do, consider changing the API to take a function object, similar to what functions from the standard C++ library do.
Finally, there is a common approach used in C libraries that take function pointers - passing an additional void* pointer, which will be passed back in a call to your function pointer; pthreads library does that. If this is the case, you can create a struct that wraps the invocation target object, and pass a pointer to this struct to be passed back to your static function.
AFAIK I don't think there is any other way. You will have to make the method static.
I'm using a C library inside my C++ app. The library has a function with the following signature:
void awe_webview_set_callback_js_callback(awe_webview* webview, void (*callback)(awe_webview* caller, const awe_string* object_name, const awe_string* callback_name, const awe_jsarray* arguments));
I'm trying to set a function as a call back and I'd like to be able to use the following class member function
void BattleScreen::HandleWebViewCallbacks(awe_webview* WebView, const awe_string* object, const awe_string* callback, const awe_jsarray* arguments)
{
//handling code
}
I can't bind it directly and based on here http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2 I have a possible solution where I'd create a static member to handle the callback (since based on that site, it should be fine) and add a static instance of this class for the static member to call on.
i.e. add the following to BattleScreen:
static BattleScreen* callbacktarget;
static BattleScreen::TopLevelHandleWebViewCallbacks(awe_webview* WebView, const awe_string* object, const awe_string* callback, const awe_jsarray* arguments)
{
callbacktarget->HandleWebviewCallbacks(WebView, object, callback, arguments);
}
bind it in the constructor like so:
awe_webview_set_callback_js_callback(this->GetWebView(), static_cast<void (*)(awe_webview*, const awe_string*, const awe_string*, const awe_jsarray*)>(&BattleScreen::TopLevelHandleWebViewCallbacks));
and assign the object to callbacktarget in the constructor.
BattleScreen::callbacktarget = this;
The problem is I have no way of knowing how many of these classes I will have at any one time (It'll be minimal but possibly greater then 1). I considered making the callbacktarget a vector of BattleScreen* that i can iterate through inside TopLevelHandleWebViewCallbacks and compare like so:
if (callbacktargets[index]->GetWebview() == WebView)
{
callbacktargets[index]->HandleWebviewCallbacks(WebView, object, callback, arguments);
}
but the problem here is that I'm only comparing the awe_webview pointers which seems like a really bad idea. The library is closed source and the awe_webview's are C constructs so I can't see what makes them up and if there are any properties that would make a more suitable comparison. Is there a good solution to this?
If I'm being unclear or you need additional information let me know.
Thanks in advance
The fact that callbacks receive awe_webview pointer more or less proves that comparing them is what they expect you to do.
However, I would modify your solution to use a global map between webviews to BattleScreens:
static std::map<awe_webview*, BattleScreen*> gWebViewBattleScreen;
Then have one global callback that picks the BattleScreen object from it and calls its method:
static void webviewCallback(awe_webview* caller, ......)
{
if (gWebViewBattleScreen.find(caller) != gWebViewBattleScreen.end())
gWebViewBattleScreen[caller]->HandleWebViewCallbacks(......)
}
Nice libraries allow you to pass a context pointer with the callback, so you can assign something like BattleObject* to each callback you set:
void set_nice_callback(void (*callback)(Params params, void* context), void* context);
The library you are using does not seem to be very nice :) You may want to point its developers to this.
Three solution:
Verify that the library doesn't allow you to bind arbitrary 'context' pointer to each awe_webview. They usually do. If it does, store there the pointer to BattleScreen and when the static callback is called, retrieve this pointer from the 'context' of webview and call the member function on this pointer.
Use a global map<awe_webview*, BattleScreen*>. In the static callback, find the BattleScreen corresponding to the webview. Requires locking of the global map, not pretty.
Note: using a pointer to webview as a unique id is almost surely OK. It's always unique.
Use thunks (e.g. http://www.codeproject.com/KB/cpp/thunk32.aspx).
I was trying to declare a callback function in class and then somewhere i read the function needs to be static but It didn't explain why?
#include <iostream>
using std::cout;
using std::endl;
class Test
{
public:
Test() {}
void my_func(void (*f)())
{
cout << "In My Function" << endl;
f(); //Invoke callback function
}
static void callback_func()
{cout << "In Callback function" << endl;}
};
int main()
{
Test Obj;
Obj.my_func(Obj.callback_func);
}
A member function is a function that need a class instance to be called on.
Members function cannot be called without providing the instance to call on to. That makes it harder to use sometimes.
A static function is almost like a global function : it don't need a class instance to be called on. So you only need to get the pointer to the function to be able to call it.
Take a look to std::function (or std::tr1::function or boost::function if your compiler doesn't provide it yet), it's useful in your case as it allow you to use anything that is callable (providing () syntax or operator ) as callback, including callable objects and member functions (see std::bind or boost::bind for this case).
Callbacks need to be static so that they don't have an implicit this parameter as the first argument in their function signature.
Non-static methods require a 'this' instance, and can only be called upon an object instance.
However, it is possible to use non-static callbacks, but they are syntactically much harder to write. See http://www.newty.de/fpt/callback.html#member for an explanation.
Marshal Cline gives you the complete answer here
. The whole section contains everything you need to know.
To summarize it can explain that you need a static member because the this pointer isn't needed (unlike normal member methods). But it also covers that using a static may not be enough for all compilers since C++ calling convention might be different between C and C++.
So the recommendation is to use an extern "C" non-member function.
It needs to be static so that the function signature matches. When a member function is called, a hidden parameter is included in the call (i.e. the "this" pointer). In static member functions the this pointer is not passed as a parameter.
If you use function pointers, the runtime environment can't pass a reference to an instance when calling the function. But you may use std::mem_fun<>, in to use functors and member methods.