从绑定调用方法会给出“调用不匹配”错误

问题描述 投票:0回答:1

我正在尝试为 Gtk 单击信号制作一个包装器以挂钩到我的事件系统。 Gtk 处理点击事件的方式是这样的:

auto button = new Gtk::Button();
button->signal_clicked().connect(...);

因此,为了将其添加到我的系统中,我创建了一个名为

fromSignal
的函数,它接受两个输入,我将它们绑定在一起。我遇到的问题是在
callback();
线上。

error: no match for call to '(std::_Bind<Glib::SignalProxy<void()> (Gtk::Button::*(Gtk::Widget*))()>) ()'
[build]    18 |   callback();
[build]       |   ~~~~~~~~^~

这是包装纸:

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);
}

我尝试更改

_signalCallabck
的定义,然后出现以下错误:

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*))()>

正确的做法是什么?我是不是把这个问题搞得太复杂了?

c++ gtkmm
1个回答
0
投票

模板会产生混乱的错误消息。我建议对您的示例代码进行三种简化。

首先,由于

_signalCallback
只会调用它的参数,因此很容易内联。所以
_signalCallback<T>(b)
变成了
b()
。消除了一个模板。其次,我们可以将
fromSignal
函数模板替换为指定模板参数
Gtk::Button
的函数。另一个模板被淘汰。然而,还有一个模板与错误消息混淆,即
std::bind

第三种简化是去掉

std::bind
并写出等价表达式。 (我还将添加一个别名,以使签名更易于阅读。

using RetType = Glib::SignalProxy<void()>;

void fromSignal(Gtk::Widget* widget, RetType (Gtk::Button::*f)()) {
  (widget->*f)();
}

编译它会给出更丰富的错误消息:

错误:指向成员类型的指针

RetType (Gtk::Button::)()
{aka 'Glib::SignalProxy (Gtk::Button::)()'} 与对象类型不兼容
Gtk::Widget

编译器正在抱怨,因为您不能采用任意

Widget
并期望它具有来自
Button
的成员。基类不能用于调用派生类的方法。您需要一个派生类指针来调用派生类的成员函数。

将第一个参数的类型从

Gtk::Widget*
更改为
T*
,使其与第二个参数的类型对应。

template <typename T>
void fromSignal(T* widget, Glib::SignalProxy<void()> (T::*f)()) {
  auto b = std::bind(f, widget);
  _signalCallback<T>(b);
}

lambda 可能会使代码更易于阅读。

template <typename T>
void fromSignal(T* widget, Glib::SignalProxy<void()> (T::*f)()) {
  _signalCallback<T>([widget, f]() { return (widget->*f)(); });
}
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.