I have the class stickyNotes
, and in it I have the function addNote
which is a public non-static function.
In the code there is a new type defined:
typedef void(*fptr)
I also have the class Button
which in its constructor takes a variable of type fptr
, I have a function makeButton()
that returns a Button
object.
stickyNotes
also has another member called rendermainWindow
which renders the main window and adds a button, I am trying to create a new variable of type fptr
that is set to the address of stickyNotes::addNote
and I'm getting the error:
'&': illegal operation on bound member function expression
stickyNotes::rendermainWindow
:
void stickyNotes::rendermainWindow() {
/*
Renders the main window
*/
this->buttonList.empty(); // buttonList is a list of all buttons
mainWindow->clear(sf::Color(29, 29, 27, 255)); // clearing the window
sf::Vector2u windowDimensions = mainWindow->getSize(); // getting window dimensions
fptr cb = &this->addNote; <-------- ERROR HERE
Button plusB = makeButton((int)(windowDimensions.x * 0.75),
(int)(windowDimensions.y * 0.15),
(int)(windowDimensions.x * 0.85),
(int)(windowDimensions.y * 0.25),
mainWindow,
cb);
// first button to add stuff
std::vector<Button> vect;
vect.push_back(plusB);
this->buttonList.push_back(vect);
renderNotes();
}
Replacing this->addNote
with stickyNotes::addNote
.
I'm not looking to make addNote static. and I want to keep it public, how can I make a button with the callback function of addNote? if there is a workaround, I'll be glad to hear it.
You are trying to pass a callback to the button. If you require the callback to be a simple function pointer (that does not receive any arguments) then your callback cannot retain any state.
However, all non-static member functions require at least one piece of state in order to be called: They need to know which object to work in/with.
These two are fundamentally at odds: If your button takes a simple function pointer, it cannot be used to call member functions (leaving horrible hacks such as global state aside).
One way around this is to use member function pointers: These specify which class they operate on (i.e. are member functions of) and must be called on an instance of that class. Since you presumably want the button callback to be usable with more than one class, you can use polymorphy - this is the interface solution SHR suggested.
Another option for the button interface is to take (and store) a std::function<void()>
instead of your function pointer. std::function
can store state and is very conveniently used with lambda functions:
Button plusB = makeButton(/* ... */, [this]() { addNote(); });
Lastly, you could allow users to pass some "custom data" to the button interface, possibly as void*
or std::any
which is passed along to the callback. The user can then store e.g. the stickyNotes
instance in that custom data. That is compatible with a simple function pointer. However, this approach circumvents type safety and is very low-level. It is used in some libraries as it is very general, but it's much more annoying to work with than the std::function
approach.