从lambda到模板功能指针的蹦床

trampoline from lambda to a template function pointer

本文关键字:指针 功能 lambda      更新时间:2023-10-16

我正在包装C库,并希望使用回调的功能指针的参数列表来确定如何在异步调用的另一侧施放void*。问题是我无法弄清楚如何从Lambda蹦床中访问模板化回调。以下是带有评论的示例代码,其中编译器错误正在发生,但是无效的代码应该给出我要做的事情的想法。

// Hypothetical asynchronous C library call
typedef void (*future_cb)(void* data);
void call_in_the_future(future_cb cb, void* data) {
  cb(data);
}
struct Mine { /* For sake of the example */ };
struct Wrapper {
  Wrapper() : ptr_(nullptr) { }
  template <typename DataType>
  void run(void (*cb)(Wrapper* wrap, DataType other), DataType ptr) {
    auto lcb = [](void* data) {
      Wrapper* wrap = static_cast<Wrapper*>(data);
      DataType other = static_cast<DataType>(wrap->ptr_);
      /***** Compiler error here *****/
      cb(wrap, other);
    };
    ptr_ = ptr;
    // Call the hypothetical asynchronous C library function.
    call_in_the_future(lcb, this);
  }
  void* ptr_;
};
// Looking to store each type and cast them for this callback.
static void wrapper_cb(Wrapper* wrap, Mine* me) { }
int main() {
  Mine* me = new Mine();
  Wrapper* wrap = new Wrapper();
  wrap->run(wrapper_cb, me);
}

这是构建错误:

main5.cc:19:7: error: variable 'cb' cannot be implicitly captured in a lambda with no capture-default specified
      cb(wrap, other);
      ^
main5.cc:13:19: note: 'cb' declared here
  void run(void (*cb)(Wrapper* wrap, DataType other), DataType ptr) {
                  ^
main5.cc:14:16: note: lambda expression begins here
    auto lcb = [](void* data) {
               ^
main5.cc:19:7: error: variable 'cb' cannot be implicitly captured in a lambda with no capture-default specified
      cb(wrap, other);
      ^
main5.cc:37:9: note: in instantiation of function template specialization 'Wrapper::run<Mine *>' requested here
  wrap->run(wrapper_cb, me);
        ^
main5.cc:13:19: note: 'cb' declared here
  void run(void (*cb)(Wrapper* wrap, DataType other), DataType ptr) {
                  ^
main5.cc:14:16: note: lambda expression begins here
    auto lcb = [](void* data) {
               ^
2 errors generated.

编辑:如果我尝试在lambda中捕获cb,则存在编译错误:

error: no matching function for call to 'call_in_the_future'

编辑2:为了清楚,我明白为什么这两个构建错误正在发生。我想知道是否有解决这些问题的方法,所以我可以致电cb

您的捕获列表为空。 cb未传递到lambda。因此无法使用。

auto lcb = [](void* data) {
  Wrapper* wrap = static_cast<Wrapper*>(data);
  DataType other = static_cast<DataType>(wrap->ptr_);
  /***** Compiler error here *****/
  cb(wrap, other);
};

lambda表达式

下一个错误发生,因为只有一个没有捕获任何东西的lambda可以用作固定功能调用。

c lambda带有捕获作为功能指针将lambda作为功能指针

传递

您还必须将回调存储在包装器中,例如:

struct Wrapper {
    template <typename DataType>
    void run(void (*cb)(Wrapper*, DataType*), DataType* ptr) {
        auto lcb = [](void* userdata) {
            Wrapper* wrap = static_cast<Wrapper*>(userdata);
            auto* cb = reinterpret_cast<void(*)(Wrapper*, DataType*)>(wrap->cb_);
            DataType* other = static_cast<DataType*>(wrap->ptr_);
            cb(wrap, other);
        };
        cb_ = reinterpret_cast<void(*)()>(cb);
        ptr_ = ptr;
        // Call the hypothetical asynchronous C library function.
        call_in_the_future(lcb, this);
    }
    void (*cb_)() = nullptr; // Cannot use void* to erase type of function pointer
    void* ptr_ = nullptr;
};

或不施放回调:

class Wrapper {
private:
    class IFunc
    {
    public:
        virtual ~IFunc() =  default;
        virtual void Call() const = 0;
    };
    template <typename DataType>
    struct Func : IFunc
    {
        Func(void (*cb)(Wrapper*, DataType*), DataType* ptr, Wrapper* wrapper) :
            cb(cb), ptr(ptr), wrap(wrapper) {}
        void Call() const override { cb(wrap, ptr); }
        static void CallFromVoidP(void* that)
        {
            static_cast<Func*>(that)->Call();
        }
        void (*cb)(Wrapper*, DataType*);
        DataType* ptr;
        Wrapper* wrap;
    };
public:
    template <typename DataType>
    void run(void (*cb)(Wrapper*, DataType*), DataType* ptr) {
        func = std::make_unique<Func<DataType>>(cb, ptr, this);
        // Call the hypothetical asynchronous C library function.
        call_in_the_future(&Func<DataType>::CallFromVoidP, func.get());
    }
    std::unique_ptr<IFunc> func;
};