I am trying to make a wrapper for a Gtk click signal to hook into my event system. The Gtk way to handle click events would be like this:
auto button = new Gtk::Button();
button->signal_clicked().connect(...);
So, to add it to my system I created a function called fromSignal which takes two inputs and I will bind them together. The problem that I am running into is on the callback(); line.
error: no match for call to '(std::_Bind<Glib::SignalProxy<void()> (Gtk::Button::*(Gtk::Widget*))()>) ()'
[build] 18 | callback();
[build] | ~~~~~~~~^~
Here is the wrapper:
template <typename T>
void _signalCallback(_Bind<Glib::SignalProxy<void()> (T::*(Widget*))()> callback) {
callback();
printf("callback\n");
}
template <typename T>
void fromSignal(Gtk::Widget* widget, Glib::SignalProxy<void()> (T::*f)()) {
auto b = std::bind(f, widget);
_signalCallback<T>(b);
}
void main() {
auto button = new Gtk::Button();
fromSignal<Gtk::Button>(button, &Gtk::Button::signal_clicked);
}
I tried changing the definition of _signalCallabck which then gives me the following error:
void _signalCallback(function<Glib::SignalProxy<void()>()> callback);
// The error message:
error: could not convert 'b' from 'std::_Bind<Glib::SignalProxy<void()> (Gtk::Button::*(Gtk::Widget*))()>' to 'std::function<Glib::SignalProxy<void()>()>'
[build] 26 | _signalCallback<T>(b);
[build] | ^
[build] | |
[build] | std::_Bind<Glib::SignalProxy<void()> (Gtk::Button::*(Gtk::Widget*))()>
What is the correct way to do this? Am I overly complicating this?
Templates make a mess of error messages. I propose three simplifications to your example code.
First, since
_signalCallbackwill just invoke its parameter, it's easy to inline. So_signalCallback<T>(b)becomesb(). One template eliminated. Second, we can replace thefromSignalfunction template with a function for the specified template argument,Gtk::Button. The other template eliminated. However, there is one more template messing with the error message, namelystd::bind.The third simplification is to drop
std::bindand write out the equivalent expression. (I'll also throw in an alias to make the signature easier to read.Compiling this gives a more informative error message:
The compiler is complaining because you cannot take an arbitrary
Widgetand expect it to have a member fromButton. Base classes cannot be used to invoke a method of a derived class. You need a derived class pointer to invoke a member function of the derived class.Change the type of the first parameter from
Gtk::Widget*toT*so that it corresponds to the type of the second parameter.A lambda might make the code easier to read.
If you don't like the syntax to invoke a pointer-to-member (which some people find clunky):