我想从gtk 中使用 g_signal_connect()
的lambdas。 传统上,这样的工作是设置回调函数:
#include <gtk/gtk.h>
#include <iostream>
void my_callback(GtkApplication *app, gpointer user_data)
{
std::cout << "test1" << std::endl;
}
void test1()
{
GtkApplication *app = gtk_application_new(nullptr, G_APPLICATION_NON_UNIQUE);
void * data = nullptr; // simple example
g_signal_connect(app, "activate", G_CALLBACK(my_callback), data);
}
上面的测试与g++ $(pkg-config --cflags --libs gtk+-3.0) test.cpp
编译以获取必要的GTK -3.0定义。
在尝试将my_callback1()
转换为lambda时,我尝试了这种变体:
void test2()
{
GtkApplication *app = gtk_application_new(nullptr, G_APPLICATION_NON_UNIQUE);
void * data = nullptr; // simple example
// use lambda instead of call to explicit function
g_signal_connect(app, "activate",
G_CALLBACK(
[](GtkApplication *application, gpointer user_data)
{
std::cout << "test2" << std::endl;
}
), data);
}
上面的test2()
代码产生以下编译错误:
/usr/include/glib-2.0/gobject/gclosure.h:70:41: error: invalid cast
from type ‘test2()::<lambda(GtkApplication*, gpointer)>’
to type ‘GCallback {aka void (*)()}’
有没有办法将C lambda指定为回调函数?我不明白修复这种"无效的演员"需要什么。
当您查看G_CALLBACK
的定义时,您会发现它只是void (*)()
的铸件。这是GTK 在收到的指针类型上采用一种类型擦除形式,删除参数列表。
lambda定义了(闭合(对象类型。这不是功能。虽然无捕获的lambda确实具有与函数指针的隐式转换操作员,但该指针具有与lambda的参数列表相匹配的签名。
因此,您可以将lambda转换为void(*)(GtkApplication*, gpointer)
,而不是直接转换为void (*)()
,因为它是完全无关的类型。
解决方法是将lambda转换为功能指针类型,然后将其馈送给G_CALLBACK
作为铸件。一个整洁的技巧是在lambda之前附加+
:
g_signal_connect(app, "activate",
G_CALLBACK(
+[](GtkApplication *application, gpointer user_data)
{
std::cout << "test2" << std::endl;
}
), data);
由于lambdas的Unary 没有超载,因此编译器会有所帮助,并为我们提供指针(可以应用于Unary (。之后,宏中的铸件应起作用。
问题是指针类型的不匹配,正如错误消息清楚地说明:
invalid cast from type ‘test2()::<lambda(GtkApplication*, gpointer)>’
^ accepting 2 parameters^
to type ‘GCallback {aka void (*)()}’
^ no parameter...
现在更有趣的问题是:为什么第一次尝试工作?好吧,显然,转换宏中施放的C样式充当了另一个功能指针的reinterpret_cast
。对于原始功能指针而言,这是可能的,但是,lambdas ...
要四处走动,必须将lambda首先施放为适当的功能指针;您可以尝试此代码以进行插图:
int main(int argc, char* argv[])
{
void(*f)(void) = reinterpret_cast<void(*)(void)>
(
static_cast<void(*)(int)>([](int n){ std::cout << n; })
);
reinterpret_cast<void(*)(...)>(f)(7);
std::cout << std::endl;
return 0;
}
(使用的C 铸造而不是在此处铸造的C样式(。