Cannot call member function without object - ofxGuiExtended

Hello. I am trying to add a listener to a button of ofxGuiExtended, which calls a function from another class different from ofApp. My class is called Layer

#pragma once

#include "ofMain.h"

class Layer {

public:

    Layer();

    void drawLayer();

};

on my ofApp.h I declare an instance of Layer, called layerTest, the buttons and components of the GUI, and a method called setupGui(), which simplified looks like this:

void ofApp::setupGui(){
    buttonsContainer = projectPanel->addContainer();
    drawLayerButton = buttonsContainer->add<ofxGuiButton>("Draw Layer", ofJson({{"type", "fullsize"}, {"text-align", "center"}}));
    drawLayerButton->addListener(&layerTest, &Layer::drawLayer());
}

The compiler says that

cannot call member function ‘void Layer::drawLayer()’ without object
  132 |     drawLayerButton->addListener(&layerTest, &Layer::drawLayer());
      |                                                                                  ^

Any ideas on why this is happening? Shouldn’t layerTest be understood as the object?

Hi,
I think this should be…

drawLayerButton->addListener( &layerTest, &Layer::drawLayer );

…without the parenthesis after the method name.

Thanks a lot. It worked. But I still don’t understand why the parenthesis are an issue. What would happen if I call a function with arguments?

Let’s say you have a function foo like that:

int foo(){
    return 3;
}

Then, foo() call the fonction and foo without the parenthesis is a pointer to the function.
In other terms, foo() is the result of the fonction being executed, foo is the function itself.

addListener() need to know which function you want to call when the event happens. This is why you must pass a function pointer.

Now, the syntax to get a pointer to a function that is a class method is different.

class A {
public:
    int foo(){
        return 3;
    }
}

To get a foo pointer you must write &A::foo
In your case: &Layer::drawLayer

When you write: &Layer::drawLayer() you are saying: “execute drawLayer() now, and give me its result”. This is not what you want, but this is also a nonsense: the function drawLayer() can’t be executed “alone”, it need to know on which Layer object it would operate, because the function pointer is just the adress of a piece of compiled code somewhere in the memory and that code operate on the datas of a Layer object. This is why the error message was "cannot call member function ‘void Layer::drawLayer()’ without object".
I guess this is hard to really understand this last part without a longer explanation, you can easily find tutorials about the C++ functions pointers topic.

Thanks a lot for the explanation. I think I understand most of it, but let’s say for example that the class method takes arguments:

class A {
public:
    int foo(int &arg1, int &arg2){
        return arg1 + arg2;
    }
}

How would you specify which arguments to pass to the function pointer in the listener? I’m reading the reference you linked but I’m struggling a bit, do I have to dereference the function pointer?

For a button, addListener() expects a function with no parameters. So you can only do:

drawLayerButton->addListener(&layerTest, &Layer::drawLayer);

class Layer {
public:
    void drawLayer();
}

If you want to call another function with arguments you can call it inside drawLayer():

void Layer::drawLayer(){
    draw( "a dog" );
}
void Layer::draw( const string & message ){
    ofLogNotice() << "I draw " << message;
}

Or:

drawLayerButton->addListener( this, &ofApp::drawLayer);

void ofApp::drawLayer(){
    layerTest.draw( "a dog" );
}

void Layer::draw( const string & message ){
    ofLogNotice() << "I draw " << message;
}