Pass an objects member function as argument (function pointer) - c++

I have a pointer to an object 'eventHandler' which has a member function 'HandleButtonEvents':
I call it like this:
eventHandler->HandleButtonEvents();
Now I want to pass a pointer to the member-function 'HandleButtonEvents()' of the class 'EventHandler' as an argument to another the object 'obj' like in this Stackoverflow example:
ClassXY obj = ClassXY(eventHandler->HandleButtonEvents);
The constructor is declared like this:
ClassXY(void(*f)(void));
The compiler tells me:
error : invalid use of non-static member function
What am I doing wrong?

Using std::function and std::bind as suggested in my comment makes it very easy:
#include <iostream>
#include <functional>
class ClassXY
{
std::function<void()> function;
public:
ClassXY(std::function<void()> f)
: function(f)
{}
void call()
{
function(); // Calls the function
}
};
class Handler
{
public:
void HandleButtonEvent()
{
std::cout << "Handler::HandleButtonEvent\n";
}
};
int main()
{
Handler* handler = new Handler;
ClassXY xy(std::bind(&Handler::HandleButtonEvent, handler));
xy.call();
}
See here for a live example.

Related

How to deduce the template argument when storing a lambda-templated class as a member of another class?

I have a question about storing a lambda-templated object as a class member. The Invoker class is a templated class storing an arbitrary lambda function. I want to store an instance of an Invoker in another class, Worker. However, I do not know how to fill the template argument TCallback when the Invoker is used as a class member. It does not deduce like the first line in the main function. As shown in the comments, I am trying to define a lambda somewhere in Worker and pass it to its member of the type Invoker.
What I have tried is to use decltype of a class method but it could not be invoked like a generic lambda - it needs the class object context to run.
Much appreciated for any ideas and maybe some workarounds.
Thank you.
#include <iostream>
template <typename TCallback>
struct Invoker {
explicit Invoker(TCallback&& cb) : cb(cb) {}
TCallback cb;
void invoke() {
cb();
}
};
struct Worker {
void some_callback() {
std::cout << "callback in worker\n";
}
// Not working: some_callback is a member function and can only be called with the context object
Invoker<decltype(&Worker::some_callback)> invoker{&Worker::some_callback};
// How to make a something like this?
// auto lambda_in_class = [&]{some_callback()};
// Invoker<decltype(lambda_in_class)> invoker{lambda_in_class};
};
int main() {
Invoker invoker([]{std::cout << "invoker\n";});
Worker worker;
worker.invoker.invoke();
return 0;
}
Do you really need to use remplates? This works:
#include <iostream>
#include <functional>
struct Invoker {
explicit Invoker(std::function<void()> cb) : cb(cb) {}
std::function<void()> cb;
void invoke() {
cb();
}
};
struct Worker {
void some_callback() {
std::cout << "callback in worker\n";
}
// Not working: some_callback is a member function and can only be called with the context object
Invoker invoker{std::bind(&Worker::some_callback, this)};
// How to make a something like this?
std::function<void()> lambda_in_class = [&]{some_callback();};
Invoker invoker1{lambda_in_class};
};
int main() {
Invoker invoker([]{std::cout << "invoker\n";});
Worker worker;
worker.invoker.invoke();
worker.invoker1.invoke();
return 0;
}
You can do it with templates as well, but you will need template deduction guide (which is C++17 feature) for lambdas:
#include <iostream>
#include <functional>
template <typename TCallback>
struct Invoker {
explicit Invoker(TCallback cb) : cb(cb) {}
TCallback cb;
void invoke() {
cb();
}
};
template<typename T>
Invoker(T) -> Invoker<T>;
struct Worker {
void some_callback() {
std::cout << "callback in worker\n";
}
// Not working: some_callback is a member function and can only be called with the context object
Invoker<decltype(std::bind(&Worker::some_callback, static_cast<Worker *>(0)))> invoker{std::bind(&Worker::some_callback, this)};
// How to make a something like this?
// auto lambda_in_class = [&]{some_callback()};
// Invoker<decltype(lambda_in_class)> invoker{lambda_in_class};
};
int main() {
Invoker invoker([]{std::cout << "invoker\n";});
Worker worker;
worker.invoker.invoke();
return 0;
}
Lambda inside class will only work with std::function, since it is impossible to use auto for class member and you can't define its type any other way.
For member functions, to simplify its usage you even can create special constructor and deduction guide. Like this:
// Add constructor to Invoker definition
template<typename T>
Invoker(void (T::*func)(), T* obj) : cb(std::bind(func, obj)) {}
// Add template guide after Invoker definition
template<typename T>
Invoker(void (T::*func)(), T* obj) -> Invoker<decltype(std::bind(func, obj))>;
// Now you can declare invoker in Worker like this
decltype(Invoker(&Worker::some_callback, static_cast<Worker *>(0))) invoker{&Worker::some_callback, this};
// Or outside, like this
Worker worker;
auto invoker = Invoker{&Worker::some_callback, &worker};
The problem with:
Invoker<decltype(&Worker::some_callback)> invoker{&Worker::some_callback};
is that some_callback is a non-static member function. When you call it, an implicit this pointer is actually passed to it. So when you call it through the member function pointer, an object of Worker is required(which does not exist in your Invoker class.
One workaround is to use a bind expression to bind a this pointer with the some_callback:
std::bind(&Worker::some_callback, this)
And the result type can then be converted to a std::function<void()> and stored in Worker.invoker:
Invoker<std::function<void()>> invoker{std::bind(&Worker::some_callback, this)};
Demo
Another solution is to use a static member function instead. By using a static function, you would not need to pass a this pointer anymore, and you can initialize invoker directly with &Worker::some_callback:
Invoker<std::function<void()>> invoker{&Worker::some_callback};
Demo

Pass member function pointer to parent class yields compiler error

I'd like to have child classes register callbacks to their parent class so that users of the parent class can call methods of the child with a known function signature.
typedef int(*Func)(int);
class A
{
public:
void registerFunc(Func f)
{}
};
class B : public A
{
public:
B()
{
A::registerFunc(&B::myF);
}
int myF(int x) {
// do stuff with member variables
return 3;
}
};
But I get this compiler error
main.cpp:18:23: error: cannot initialize a parameter of type 'Func' (aka 'int (*)(int)') with an rvalue of type 'int (B::*)(int)'
A::registerFunc(&B::myF);
^~~~~~~
main.cpp:8:28: note: passing argument to parameter 'f' here
void registerFunc(Func f)
Here's a Repl illustrating the error in a concise example.
https://replit.com/#Carpetfizz/RudeSmoothComments#main.cpp
The accepted answer in a related thread suggested to override a virtual function declared in A but my use case actually requires dynamic callback registrations.
You can try this.
typedef std::function<int (int)> Func;
class A
{
public:
void registerFunc(Func f)
{}
};
class B : public A
{
public:
B()
{
A::registerFunc(std::bind(&B::myF, *this, std::placeholders::_1));
}
int myF(int x) {
// do stuff with member variables
return 3;
}
};
If I understand the goal (and believe me, that's a sketchy 'if'), you want to specify some member of some A derivation to invoke from some A member as a dispatched 'callback' mechanic. If that is the case, then to answer your question in comment, yes, a function and bind can do this. It can even be semi-protected with a little help from sfinae:
Example
#include <iostream>
#include <type_traits>
#include <functional>
#include <memory>
struct A
{
virtual ~A() = default;
std::function<void(int)> callback = [](int){};
template<class Derived>
std::enable_if_t<std::is_base_of<A, Derived>::value>
registerCallback(void (Derived::*pfn)(int))
{
using namespace std::placeholders;
callback = std::bind(pfn, dynamic_cast<Derived*>(this), _1);
}
void fire(int arg)
{
callback(arg);
}
};
struct B : public A
{
void memberfn(int arg)
{
std::cout << __PRETTY_FUNCTION__ << ':' << arg << '\n';
}
};
struct Foo
{
void memberfn(int arg)
{
std::cout << __PRETTY_FUNCTION__ << ':' << arg << '\n';
}
};
int main()
{
std::unique_ptr<A> ptr = std::make_unique<B>();
ptr->registerCallback(&B::memberfn);
// ptr->registerCallback(&Foo::memberfn); // WILL NOT WORK
ptr->fire(42);
}
Output
void B::memberfn(int):42
The Parts
The first part is straight forward. We declare a member variable callback to be a std::function<void(int)> instance. This is where we'll eventually bind our callable object point. The default value is a lambda that does nothing.
The second part is... a little more complicated:
template<class Derived>
std::enable_if_t<std::is_base_of<A, Derived>::value>
registerCallback(void (Derived::*pfn)(int))
This declares registerCallback as an available member function that accepts a non-static member function pointer taking one int as an argument, but only if the class hosting that member function, or a derivative therein, is a derivation of A (or A itself). Some non-A derivative Foo with a member void foo(int) will not compile.
Next, the setup to the callback itself.
using namespace std::placeholders;
callback = std::bind(pfn, dymamic_cast<Derived*>(this), _1);
This just binds the pointer-to-member to this dynamic-cast to the derivation type (which had better work or we're in trouble, see final warning at the end of this diatribe), and sets the call-time placeholder. The _1 you see comes from the std::placeholders namespace, and is used to delay providing an argument to the callback until such time as we actually invoke it (where it will be required,and you'll see that later). See std::placehholders for more information.
Finally, the fire member, which does this:
void fire(int arg)
{
callback(arg);
}
This invokes the registered function object with the provided argument. Both the member function and this are already wired into the object. The argument arg is used to fill in the placeholder we mentioned earlier.
The test driver for this is straightforward:
int main()
{
std::unique_ptr<A> ptr = std::make_unique<B>();
ptr->registerCallback(&B::memberfn);
// ptr->registerCallback(&Foo::memberfn); // WILL NOT WORK
ptr->fire(42);
}
This creates a new B, hosting it in a dynamic A pointer (so you know there is no funny business going on). Even with that, because B derived from A the registerCallback sfinae filtering passes inspection and the callback is registered successfully. We then invoke the fire method, passing our int argument 42, which will be sent to the callback, etc.
Warning: With great power comes great responsibility
Even those there is protection from passing non-A derived member functions, there is absolutely none from the casting itself. It would be trivial to craft a basic A, pass a B member (which will work since A is its base), but there is no B actually present.
You can catch this at runtime via that dynamic_cast, which we're currently not error checking. For example:
registerCallback(void (Derived::*pfn)(int))
{
using namespace std::placeholders;
Derived *p = dynamic_cast<Derived*>(this);
if (p)
callback = std::bind(pfn, p, _1);
}
You can choose the road more risky. Personally, i'd detect the null case and throw an exception just to be safe(er)

How to change a Callback signature that also accepts class methods and free functions?

I have a Callback which looks like this:
typedef void(*Callback)(EventInfo event_info);
This can be used with free functions, but when I try to use class methods it fails with the error :
Error C2276 '&': illegal operation on bound member function expression
How should I go about this and make it so that it also accepts a class method just like a free function. That is I could simply do :
struct MyClass
{
void some_methods(EventInfo info)
{
sth;
}
}
void some_functions(EventInfo info)
{
sth;
}
int main()
{
MyClass obj;
myobj.AddOnSthChanged(obj.somemethods);
myobj.AddOnSthChanged(some_functions);
...
Pointers on function are limited to .. pointers on function.
To allow any callable, you have to use template or type erasure as std::function:
using Callback = std::function<void(EventInfo)>;
struct MyClass
{
Callback callback;
};
struct A
{
void foo(EventInfo) {}
};
void bar(EventInfo) {}
int main()
{
EventInfo event;
MyClass c1{bar};
c1.callback(event); // bar(event);
A a;
MyClass c2{ [&a](EventInfo event){ a.foo(event); }};
c1.callback(event); // a.foo(event);
}

How to pass function pointer (callback) and call it without knowing it's type?

I have a function pointer as a member to a pure virtual base class. I'd like to pass this pointer to a library which does not know about either of these classes, MyBase or MyClass, and then call the function pointer as a callback into MyClass. I'm writing the lib as well. I want the shared library to call a callback in MyClass.
My question is, how does one pass a function pointer as an argument to a function and have it called without knowing anything about the class itself.
I was considering a pointer to a function pointer, but wasn't sure how to cast properly.
class MyBase {
public:
virtual void callback() = 0;
void (MyBase::*callback_ptr)();
};
class MyClass : public MyBase {
public:
MyClass();
void callback() { cout << "callback called" << endl; };
};
main.cpp
{
MyClass my_class;
my_class->callback_ptr = &MyBase::callback;
lib->set_callback(my_class->callback_ptr);
}
lib.cpp
class MyLib {
public:
// how to declare the member function pointer here?
void** callback_ptr;
// how to write sig here?
set_callback(ptr) { callback_ptr = ptr }
running() {
// how to call the callback here w/o knowing it's type?
}
}
#include <iostream>
#include <functional>
using namespace std;
class Foo {
public:
void myFunction() {
cout << "Foo::myFunction()\n";
}
};
void myAPICall(std::function<void()> arg) {
arg();
}
int main(int, char**) {
Foo foo;
// Using a lambda
myAPICall( [&]() { foo.myFunction(); } );
// Using bind
myAPICall( std::bind(&Foo::myFunction, foo) );
return 0;
}
Yields:
$ g++ -std=c++11 f.cpp -o f && f
Foo::myFunction()
Foo::myFunction()
This assumes that you control the API you're calling, and it uses std::function like my code does. If it accepts a C-style function pointer rather than std::function, then you're going to have to play much different games.
To get a function pointer when you don't know the exact type of function that will be called, use std::function from the <functional> header.
class MyLib {
public:
// how to declare the member function pointer here?
std::function<void()> callback_ptr;
// how to write sig here?
void set_callback(std::function<void()> ptr) { callback_ptr = ptr; }
void running() {
callback_ptr();
}
};
To use a member function as a std::function, use std::bind:
int main()
{
MyClass my_class;
MyLib my_lib;
my_lib.set_callback(std::bind(&MyClass::callback, &my_class));
my_lib.running(); // calls my_class.callback()
}

How to pass a method as callback to another class?

I have a question regarding callbacks using tr1::function. I've defined the following:
class SomeClass {
public:
typedef std::tr1::function<void(unsigned char*, int)> Callback;
void registerCallback(Callback);
private:
Callback callback;
}
I've defined another class:
class SomeOtherClass {
void myCallback(unsigned char*, int);
}
Now I want to register my function 'myCallback' as callback at class 'SomeClass'using the method 'registerCallback'. However, it is not working. I've had a look on the boost documentation on the function and it seems legit to use (member) methods of a class for callbacks. Am I wrong?
Thanks in advance!
Member functions have an implicit first parameter, a this pointer so as to know which object to call the function on. Normally, it's hidden from you, but to bind a member function to std::function, you need to explicitly provide the class type in template parameter.
#include <functional>
#include <iostream>
struct Callback_t {
void myCallback(int)
{
std::cout << "You called me?";
}
};
class SomeClass {
public:
SomeClass() : callback() { }
typedef std::function<void(Callback_t*, int)> Callback;
// ^^^^^^^^^^^
void registerCallback(const Callback& c)
{
callback = c;
}
void callOn(Callback_t* p)
{
callback(p, 42);
}
private:
Callback callback;
};
int main()
{
SomeClass sc;
sc.registerCallback(&Callback_t::myCallback);
Callback_t cb; // we need an instance of Callback_t to call a member on
sc.callOn(&cb);
}
Output: You called me?;
Why all this complicated mumbo-jumbo?
Why not create a class as thus (for example)
Class MouseOverEventCallBack
{
public:
virtual void RunMouseOverCallback() = 0;
};
Then just create classes that inherit this class (and redefine the method RunMouseOverCallback)
Then Register function just needs to be
void registerCallback(MouseOverEventCallBack *callbackObject); // possible could use a reference
The register method will just call the method and the object will have all that it needs.
Seems a bit simpler. Let the compiler do the work with pointers to functions etc.
the function void (*)(unsigned char*, int) is a free function, which is a different type from void (SomeOtherClass::*)(unsigned char*, int), thus the error. You need an object to call the latter, while the former is a free function.
Look at the possible solutions listed in the Boost documentation
Another possibility is that your SomeOtherClass::myCallback is private, so you do not have access to it.
Use templates:
template <class T>
class B
{
public:
typedef void (T::*TCallBackFunction)(void);
void SetCallBack(T* pCallBackClass, TCallBackFunction pCallBackFunction)
{
if(pCallBackFunction && pCallBackClass)
{
m_pCallBackFunction = pCallBackFunction;
m_pCallBackClass = pCallBackClass;
}
}
void StartCallBackFunction()
{
(pCallBackClass->(*m_pCallBackFunction))();
}
private:
TCallBackFunction m_pCallBackFunction;
T* m_pCallBackClass;
};
Such like this. And use it:
...
B<MyClass> b;
b.SetCallBack(&b, &MyClass::MyFunction);
...