首页 > 解决方案 > 将 lambda 用于回调函数作为 C 函数参数

问题描述

我正在为函数编写自己的std::thread类似包装器pthread_*(用于教育目的)。我想出的构造函数如下所示:

template<class Fn, class... Args>
explicit Thread(Fn&& fn, Args&&... args) {
    using Invoker = Thread_invoker<Fn, Args...>;
    void* (* start_fn)(void*) = [](void* invoker_ptr) -> void* {
        // ...
    };

    auto invoker = std::make_unique<Invoker>(/* ... */);
    const auto err = ::pthread_create(&handle_, nullptr, start_fn, invoker.get());
    // ...
    invoker.release();
}

我做了一些基本的测试,代码有效。但后来我突然想到,C++函数理论上可以有不同于C函数的调用约定,传递start_fn函数指针pthread_create可以是UB。这个答案似乎证实了这一点。

进一步挖掘,我发现了这个问题。按照公认答案的精神,我将代码更改为:

extern "C" using Thread_start_fn = void* (void*);

Thread_start_fn* start_fn = [](void* invoker_ptr) -> void* {
    // ...
};

这个修改是否解决了问题,代码现在合法吗?

标签: c++clambdaextern-c

解决方案


这个修改是否解决了问题,代码现在合法吗?

不,它不能解决问题。您可以从 lambda 表达式获得的函数指针仅指向具有 C++ 语言链接的函数。

确定获得指向具有 C 语言链接的函数的指针的方法是使用自由函数。这是您将在流行的标准库实现中看到的方法。例如,在 libstdc++

extern "C"
  {
    static void*
    execute_native_thread_routine(void* __p)
    {
      thread::_State_ptr __t{ static_cast<thread::_State*>(__p) };
      __t->_M_run();
      return nullptr;
    }
    // ...
  }

推荐阅读