使用Lambda作为C函数参数中的回调函数

3

我正在编写类似于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可能会导致未定义行为。 这个答案 似乎证实了这一点。
进一步查找,我发现这个问题。遵循被接受的答案的精神,我将我的代码改成了这样:
extern "C" using Thread_start_fn = void* (void*);

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

这个修改是否解决了问题并使代码合法?

1个回答

4

这个修改能解决问题并且代码现在合法吗?

不行,它不能解决问题。从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;
    }
    // ...
  }

但是,如果编译器可以(假设代码可以编译)将C++函数指针转换为C函数指针,那么这是否意味着它可以被用作C函数指针? - Evg
@Evg - 如果编译器可以定义行为,那当然可以。我原本以为问题是关于这个是否总体上可靠的。 - StoryTeller - Unslander Monica
你的印象是正确的。我的评论是一个后续问题。谢谢! - Evg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接