Search code examples
c++pointer-to-membermember-functions

Error: a pointer to a bound function may only be used to call the function


I've been trying to assign a function pointer (of a class) to a member function (of another class) like this:

--- Game.h ---
#ifndef GAME_H
#define GAME_H

#include "Screen.h"

class Game
{
private:
    void (*HandleCurrentScreen)();

public:
    void SetScreen(const Screen& newScreen);
};

#endif



--- Game.cpp ---
#include "Game.h"
#include "Screen.h"

void Game::SetScreen(const Screen& newScreen)
{
    HandleCurrentScreen = newScreen.Handle;    //Produces the error
}



--- Screen.h ---
#ifndef SCREEN_H
#define SCREEN_H

class Screen
{
public:
    void Handle();
};

#endif



--- Screen.cpp ---
#include "Screen.h"

void Screen::Handle()
{
    ...
}

I get this error:

error C3867: 'Screen::Handle': function call missing argument list; use '&Screen::Handle' to create a pointer to member

It seems to work fine if HandleCurrentScreen points to a function that is also defined in the Game class. I've been looking for other people with this problem, but none seem to have it in cases like this.

A solution that might work is something like this:

Screen* p_currentScreen;

void Game::SetScreen(const Screen& newScreen)
{
    p_currentScreen = &newScreen;
}

and then instead of calling HandleCurrentScreen I can call p_currentScreen->Handle(), but this seems slightly less efficient to me.

What can I do to fix this? Should I just use a pointer to a class instead of a function pointer?

Any advice is welcome.


Solution

  • Your error tells you what to do:

    Screen::Handle': function call missing argument list; use '&Screen::Handle
    

    You should write it as:

    void Game::SetScreen(const Screen& newScreen)
    {
        HandleCurrentScreen = &Screen::Handle;
    }
    

    It will work only in case newScreen::handle is a static function. But in that case you could initialize it at compile time. Otherwise HandleCurrentScreen should be a pointer to a member function (PTMF) declared as:

    void (Screen::*HandleCurrentScreen)();
    

    Now, in order to call the function from a PTMF you need a function object as well. That makes your second solution better.

    Another option is std::bind:

    class Game
    {
    private:
        std::function<void()> HandleCurrentScreen;
    
    public:
        void SetScreen(const Screen& newScreen) {
            HandleCurrentScreen = std::bind(&Screen::Handle, &newScreen);
        }
    };