Gtk + g_signal_connect()和C ++ lambda导致“无效的转换”错误

Sté*_*ane 2 c++ gtk lambda callback

我想g_signal_connect()在Gtk +中使用lambda 。传统上,像这样工作来设置回调函数:

#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);
}
Run Code Online (Sandbox Code Playgroud)

编译上面的测试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);
}
Run Code Online (Sandbox Code Playgroud)

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 (*)()}’
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以将C ++ lambda指定为回调函数?我不了解解决此“无效类型转换”需要什么。

Sto*_*ica 6

当您查看的定义时G_CALLBACK,您会发现它只是对的强制转换void (*)()。这是Gtk +在接收到的指针类型上采用类型擦除的形式,从而删除了参数列表。

lambda定义(关闭)对象类型。这不是功能。尽管无捕获lambda确实具有对函数指针的隐式转换运算符,但该指针具有与lambda的参数列表匹配的签名。

因此,您可以将lambda转换为void(*)(GtkApplication*, gpointer),但不能将其直接转换为a ,void (*)()因为它是完全不相关的类型。

解决方法是先将lambda转换为函数指针类型,然后再将其输入进行转换G_CALLBACK。做到这一点的一个巧妙技巧是+在lambda之前附加一个:

g_signal_connect(app, "activate",
       G_CALLBACK(
           +[](GtkApplication *application, gpointer user_data)
           {
               std::cout << "test2" << std::endl;
           }
       ), data);
Run Code Online (Sandbox Code Playgroud)

由于一元+不会在lambda上重载,因此编译器会有所帮助,并为我们进行了指针转换(一元+可能适用于此)。在那之后,宏中的强制转换应该起作用。