有没有什么方法可以从“std::function”返回到指针

Is there any way to go back from `std::function` to a pointer?

本文关键字:function 返回 指针 std 方法 什么 有没有      更新时间:2023-10-16

想象一下以下场景:

typedef std::function<float(float)> A;
typedef float(*B)(float);
A foo();
void bar(B b);

你希望做一些类似于的事情

bar(foo());

显然,这是行不通的。主要是因为A可以包含一个状态,而B是一个函数指针。如果我们知道A不包含状态,并且我们希望以某种方式获得它的"意义",并将其放入可以传递给B的东西中,该怎么办?

这不可能吗?

如果您可以确保存储在A中的可调用对象是一个函数指针或一个具有空捕获列表的lambda,那么您可以通过以下方式简单地获取函数指针:

foo().target<B>();

通常,std::function可以"装箱"一些闭包(例如,某个lambda函数的值)。闭包包含代码和数据(闭合值)。因此,我认为您不能可移植地将其转换为裸函数指针。顺便说一句,因为概念上的闭包混合了代码和不提供它们的数据语言(如C)实际上需要回调(即传递带有一些额外数据的每个函数指针的约定,请参阅GTK中的具体示例)。

一些特定于实现的技巧可能会在堆栈上生成蹦床函数(例如,可能使用asmjit动态生成一些包含指向闭包的指针的机器代码等)。但这不是可移植的,也不是特定于系统的(特别是因为堆栈需要可执行)

如果我们知道A不包含一个状态,并且我们希望以某种方式将其"意义"转化为可以传递给B的东西,会怎么样?

即使这样也不够。std::function提供了一个target()成员函数,如果您知道底层函子的确切类型,就可以取回它。所以我们可以做,例如:

void print(int i) { std::cout << i; }
std::function<void(int)> f = print;
auto ptr = f.target<void(*)(int)>();  // not null
(*ptr)(42);                           // works

然而,即使我们的函子f不包含state,也不意味着它的底层类型正是void(*)(int)。它可能是一个完全不同的函数指针,在这种情况下,我们将无法将其拉出:

int square(int i) { return i*i; }
f = square;
ptr = f.target<void(*)(int)>(); // nullptr!

或者它可能是lambda,在这种情况下,我们甚至无法命名类型,更不用说提取它了:

f = [](int i){ std::cout << i; }; // same as print, right?
ptr = f.target<void(*)(int)>();   // ... nope :'(

基本上,类型擦除实际上是类型擦除。如果您需要原始的底层类型,这很可能表明设计不好。