【发布时间】:2014-02-21 08:03:17
【问题描述】:
不捕获任何内容的 C++11 lambda 可以存储在函数指针中。只需确保 lambda 接受并返回与函数指针相同的参数即可。
在GObject 库中,所有回调都具有void(*GCallback) (void) 类型。这个定义无论如何都不会影响回调的签名:
结构定义中用于回调函数的类型和 函数签名。这并不意味着所有的回调函数 必须不带参数并返回 void。所需的签名 回调函数由使用的上下文决定(例如 它所连接的信号)。使用 G_CALLBACK() 强制转换 GCallback 的回调函数。
换句话说,可以这样传递函数:
int my_function(int a, char b) {}
通过转换其类型(这就是 G_CALLBACK 所做的):
do_something(G_CALLBACK(my_function));
很遗憾,类型转换不适用于 C++11 lambda:
do_something(G_CALLBACK([](int a, char b) -> int {...});
// Cannot cast from type lambda to pointer type GCallback
是否可以使用任意类型的 C++ lambda 代替 GCallback?
更新
澄清一下,我知道如果签名匹配,lambda 可以转换为函数指针。我的问题是另一个维度。
ISO C 标准保证函数可以来回转换而不会丢失任何精度。换句话说,以下表达式是有效的:
int f(int a){...}
void (*void_f)() = (void (*)())f;
int (*restored_f)(int) = (int (*)(int))void_f;
restored_f(10);
我的问题是根据 C++11,以下表达式是否也有效:
int (*f)(int) = [](int a) -> int {};
void (*void_f)() = (void (*)())f;
int (*restored_f)(int) = (int (*)(int))void_f;
restored_f(10);
【问题讨论】:
-
我自己没有尝试过,但您可以尝试将 lambda 存储为变量 (
auto fun = [](...){...};),然后在do_something调用 (do_something(reinterpret_cast<void(*)()>(fun));) 中进行显式转换。由于我没有尝试过,我不知道它是否有效。 -
@icepack 这个问题不是关于如何使用 lambdas 代替函数指针。这是关于如何(如果可能)使用任意类型的 lambda 代替 GCallback。
-
@Kentzo 我明白这一点。如果您仔细研究该答案,您会发现并非总是可以将 lambdas 替换为 C 指针