Reputation: 656
The title is a bit misleading, but I don't know how to phrase the problem in one line.
Basically, I'm using a library that has the definition of this class:
class UCallbackWrapper {
public:
virtual UCallbackAction operator ()(const UMessage &)=0;
virtual ~UCallbackWrapper() {}
};
And I'm using a function of the library that has this declaration:
UCallbackID setCallback(UCallbackWrapper & callback, const char * tag);
So basically, it receives as argument (a reference to) an object of type UCallbackWrapper
.
If in the c++ file with the main function of the program I declare a function with the right prototype, it lets me pass it to the setCallback
function, like this:
UCallbackAction onImageCallback(const UMessage &msg)
{
// Some code here
}
int main(int argc, char *argv[])
{
setCallback(onImageCallback, "something"); // This works
}
Now, I would like to create a class instead, and use the setCallback function inside that class, passing a function that is member of that class. But if I do that, then the prototype of the function goes from
UCallbackAction onImageCallback(const UMessage &msg)
to
UCallbackAction (myClass::*)onImageCallback(const UMessage &msg)
and I can no longer pass that to setCallback.
I tried creating a lambda function, like this:
std::function<UCallbackAction(const UMessage &)> onImageCallback = [&] (const UMessage &msg) -> UCallbackAction {
// Code here
};
setCallback(onImageCallback, "something");
but still doesn't work, the compiler says:
error: no matching function for call to 'USyncClient::setCallback(std::function&, const char [8])' note: no known conversion for argument 1 from 'std::function' to 'UCallbackWrapper&'
So, I thought about creating a class that inherits from UCallbackWrapper and implements the virtual method (kinda like what I would do in Java), but I don't know how to do that in C++ (or of it's possible).
Can you guys help me out? Or maybe point out something that I'm doing wrong with the lambda function, or a workaround anyway.
Upvotes: 3
Views: 553
Reputation: 15334
Just write a class that implements the virtual function. You could also give it the ability to register itself as the callback.
class MyCallback : public UCallbackWrapper {
public:
UCallbackAction operator ()(const UMessage& message) override {
// Some code here...
}
void registerAsCallback() {
setCallback(*this, "something");
}
};
Just beware that due to the design of the library API it is your responsibility to ensure the lifetime of your class while the library might be using it:
int main() {
MyCallback mcb;
mcb.registerAsCallback();
// Cause library to use callback here...
}
Upvotes: 2
Reputation: 275740
template<class F>
struct UCallbackWrapperImpl:UCallbackWrapper {
F f;
virtual UCallbackAction operator ()(const UMessage & m)final override{
return f(m);
}
};
using upUCallback=std::unique_ptr<UCallbackWrapper>;
template<class F>
upUCallback MakeUCallback(F&& f){
return upUCallback(new UCallbackWrapperImpl<std::decay_t<F>>{std::forward<F>(f)});
}
Pass a lambda to MakeUCallback
and get a smart pointer to a UCallbackWrapper
.
MakeUCallback
retuens a smart pointer to the interface the api expects. Store this smart pointer for the lifetime of the callback. It will delete the callback object when it finally goes out of scope -- you can extend this by std::move
ing it to another upUCallback
.
To use the api, dereference the returned upUCallback
.
Note that the api is strange in that it takes a reference to a pure virtual interface. I do not know what crack those api designers are on, bjt that is not a good sign. You may have to investigate what lifetime management the api expects in their UCallbackWrapper
classes: how long are they supposed to last, who deletes them, etc.
In C++ you should always be aware of object lifetime requirements.
Upvotes: 2