Using generic std::function objects with member functions in one class

C++FunctionFunction PointersC++11Tr1

C++ Problem Overview


For one class I want to store some function pointers to member functions of the same class in one map storing std::function objects. But I fail right at the beginning with this code:

#include <functional>

class Foo {
    public:
        void doSomething() {}
        void bindFunction() {
            // ERROR
            std::function<void(void)> f = &Foo::doSomething;
        }
};

I receive error C2064: term does not evaluate to a function taking 0 arguments in xxcallobj combined with some weird template instantiation errors. Currently I am working on Windows 8 with Visual Studio 2010/2011 and on Win 7 with VS10 it fails too. The error must be based on some weird C++ rules i do not follow

C++ Solutions


Solution 1 - C++

A non-static member function must be called with an object. That is, it always implicitly passes "this" pointer as its argument.

Because your std::function signature specifies that your function doesn't take any arguments (<void(void)>), you must bind the first (and the only) argument.

std::function<void(void)> f = std::bind(&Foo::doSomething, this);

If you want to bind a function with parameters, you need to specify placeholders:

using namespace std::placeholders;
std::function<void(int,int)> f = std::bind(&Foo::doSomethingArgs, this, std::placeholders::_1, std::placeholders::_2);

Or, if your compiler supports C++11 lambdas:

std::function<void(int,int)> f = [=](int a, int b) {
    this->doSomethingArgs(a, b);
}

(I don't have a C++11 capable compiler at hand right now, so I can't check this one.)

Solution 2 - C++

Either you need

std::function<void(Foo*)> f = &Foo::doSomething;

so that you can call it on any instance, or you need to bind a specific instance, for example this

std::function<void(void)> f = std::bind(&Foo::doSomething, this);

Solution 3 - C++

If you need to store a member function without the class instance, you can do something like this:

class MyClass
{
public:
    void MemberFunc(int value)
    {
      //do something
    }
};

// Store member function binding
auto callable = std::mem_fn(&MyClass::MemberFunc);

// Call with late supplied 'this'
MyClass myInst;
callable(&myInst, 123);

What would the storage type look like without auto? Something like this:

std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable

You can also pass this function storage to a standard function binding

std::function<void(int)> binding = std::bind(callable, &testA, std::placeholders::_1);
binding(123); // Call

Past and future notes: An older interface std::mem_func existed, but has since been deprecated. A proposal exists, post C++17, to make pointer to member functions callable. This would be most welcome.

Solution 4 - C++

Unfortunately, C++ does not allow you to directly get a callable object referring to an object and one of its member functions. &Foo::doSomething gives you a "pointer to member function" which refers to the member function but not the associated object.

There are two ways around this, one is to use std::bind to bind the "pointer to member function" to the this pointer. The other is to use a lambda that captures the this pointer and calls the member function.

std::function<void(void)> f = std::bind(&Foo::doSomething, this);
std::function<void(void)> g = [this](){doSomething();};

I would prefer the latter.

With g++ at least binding a member function to this will result in an object three-pointers in size, assigning this to an std::function will result in dynamic memory allocation.

On the other hand, a lambda that captures this is only one pointer in size, assigning it to an std::function will not result in dynamic memory allocation with g++.

While I have not verified this with other compilers, I suspect similar results will be found there.

Solution 5 - C++

You can avoid std::bind doing this:

std::function<void(void)> f = [this]-> {Foo::doSomething();}

Solution 6 - C++

You can use functors if you want a less generic and more precise control under the hood. Example with my win32 api to forward api message from a class to another class.

IListener.h

#include <windows.h>
class IListener { 
    public:
    virtual ~IListener() {}
    virtual LRESULT operator()(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;
};

Listener.h

#include "IListener.h"
template <typename D> class Listener : public IListener {
    public:
	typedef LRESULT (D::*WMFuncPtr)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 
			
	private:
	D* _instance;
	WMFuncPtr _wmFuncPtr; 
			
	public:
	virtual ~Listener() {}
	virtual LRESULT operator()(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) override {
		return (_instance->*_wmFuncPtr)(hWnd, uMsg, wParam, lParam);
	}
			
	Listener(D* instance, WMFuncPtr wmFuncPtr) {
		_instance = instance;
		_wmFuncPtr = wmFuncPtr;
	}
};

Dispatcher.h

#include <map>
#include "Listener.h"

class Dispatcher {
	private:
		//Storage map for message/pointers
		std::map<UINT /*WM_MESSAGE*/, IListener*> _listeners; 

	public:
		virtual ~Dispatcher() { //clear the map }

		//Return a previously registered callable funtion pointer for uMsg.
		IListener* get(UINT uMsg) {
			typename std::map<UINT, IListener*>::iterator itEvt;
			if((itEvt = _listeners.find(uMsg)) == _listeners.end()) {
				return NULL;
			}
			return itEvt->second;
		}
						
		//Set a member function to receive message. 
		//Example Button->add<MyClass>(WM_COMMAND, this, &MyClass::myfunc);
		template <typename D> void add(UINT uMsg, D* instance, typename Listener<D>::WMFuncPtr wmFuncPtr) {
			_listeners[uMsg] = new Listener<D>(instance, wmFuncPtr);
		}

};

Usage principles

class Button {
    public:
    Dispatcher _dispatcher;
    //button window forward all received message to a listener
    LRESULT onMessage(HWND hWnd, UINT uMsg, WPARAM w, LPARAM l) {
        //to return a precise message like WM_CREATE, you have just
        //search it in the map.
        return _dispatcher[uMsg](hWnd, uMsg, w, l);
    }
};

class Myclass {
    Button _button;
    //the listener for Button messages
    LRESULT button_listener(HWND hWnd, UINT uMsg, WPARAM w, LPARAM l) {
        return 0;
    }

    //Register the listener for Button messages
    void initialize() {
        //now all message received from button are forwarded to button_listener function 
       _button._dispatcher.add(WM_CREATE, this, &Myclass::button_listener);
    }
};

Good luck and thank to all for sharing knowledge.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChristian IvicevicView Question on Stackoverflow
Solution 1 - C++Alex BView Answer on Stackoverflow
Solution 2 - C++Armen TsirunyanView Answer on Stackoverflow
Solution 3 - C++GregView Answer on Stackoverflow
Solution 4 - C++plugwashView Answer on Stackoverflow
Solution 5 - C++aggsolView Answer on Stackoverflow
Solution 6 - C++user11158633View Answer on Stackoverflow