将模板 lambda 转换为 `void *` 是否安全?

Is it safe to convert a template lambda to a `void *`?

我正在使用在汇编程序中实现的协程来实现纤程。协同程序通过 cocall 更改堆栈。

我想使用更高级别的接口在 C++ 中公开它,因为 cocall 程序集只能处理单个 void* 参数。

为了处理模板 lambda,我尝试将它们转换为 void* 并发现在编译和工作时,我想知道这样做是否安全,假设所有权语义堆栈(由纤维保存)。

template <typename FunctionT>
struct Coentry
{
    static void coentry(void * arg)
    {
        // Is this safe?
        FunctionT * function = reinterpret_cast<FunctionT *>(arg);

        (*function)();
    }

    static void invoke(FunctionT function)
    {
        coentry(reinterpret_cast<void *>(&function));
    }
};

template <typename FunctionT>
void coentry(FunctionT function)
{
    Coentry<FunctionT>::invoke(function);
}


int main(int argc, const char * argv[]) {
    auto f = [&]{
        std::cerr << "Hello World!" << std::endl;
    };

    coentry(f);
}

这样安全吗?此外,它是否有效?通过转换为 void* 我是否强迫编译器选择效率较低的表示?

此外,通过在不同的堆栈上调用 coentry(void*),但原始的 invoke(FunctionT) 已经返回,是否有可能堆栈可能无效以恢复? (类似于,我猜是在 std::thread 内调用)。

上面所做的一切都是定义的行为。唯一的性能影响是内联一些别名 thro7gh 的 void 指针可能会稍微困难一些。

但是,lambda 是一个实际值,如果存储在自动存储中,其持续时间与存储堆栈帧的持续时间一样长。

您可以通过多种方式解决此问题。 std::function 是一种,另一种是将 lambda 存储在 shared_ptr<void>unique_ptr<void, void(*)(void*)> 中。如果您不需要类型擦除,您甚至可以将 lambda 存储在具有推导类型的结构中。

前两个很简单。第三个;

template <typename FunctionT>
struct Coentry {
  FunctionT f;
  static void coentry(void * arg)
  {
     auto* self = reinterpret_cast<Coentry*>(arg);

    (self->f)();
  }
  Coentry(FunctionT fin):f(sts::move(fin)){}
};
template<class FunctionT>
Coentry<FunctionT> make_coentry( FunctionT f ){ return {std::move(f)}; }

现在让你的 Coentry 保持足够长的时间,直到任务完成。

如何管理生命周期的细节取决于问题其余部分的结构。