【问题标题】:Is there any way to go back from `std::function` to a pointer?有没有办法从`std::function`返回到指针?
【发布时间】:2016-02-25 04:05:23
【问题描述】:

想象以下场景:

typedef std::function<float(float)> A;
typedef float(*B)(float);

A foo();
void bar(B b);

您希望按照以下方式做某事:

bar(foo());

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

不可能吗?

【问题讨论】:

  • 你知道所包含的 exact 类型吗?具有给定签名的 std 函数可以包含许多无状态类型。如果是这样,也许。不,不。顺便说一句,如果你知道 std 函数包含什么,为什么不直接传递 that 类型呢?
  • 似乎std::function::target 可以返回指向该类型的指针,但前提是您知道该类型是什么。 en.cppreference.com/w/cpp/utility/functional/function/target
  • foo()float,不是函数指针。

标签: c++ function types


【解决方案1】:

一般来说,std::function 可以“装箱”一些closure(例如一些lambda function 的值)。闭包包含代码和数据(关闭的值)。所以我相信你不能可移植地将它转换成一个裸函数指针。顺便说一句,因为从概念上讲,闭包混合了不提供它们的代码和数据语言(如 C),实际上需要 callbacks(即,为每个函数指针传递一些额外数据的约定,请查看 GTK 以获得具体示例)。

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

【讨论】:

    【解决方案2】:

    如果你能保证A中存储的可调用对象是一个函数指针或者一个捕获列表为空的lambda,你可以通过这种方式简单地获取一个函数指针:

    foo().target<B>();
    

    【讨论】:

      【解决方案3】:

      如果我们知道 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 不包含状态,也不意味着它的底层类型就是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 :'(
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-12
        • 2022-01-14
        • 1970-01-01
        • 1970-01-01
        • 2016-09-10
        • 1970-01-01
        • 2013-08-05
        • 2017-03-10
        相关资源
        最近更新 更多