You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合规获取C++协程Promise已知基类的引用?

C++协程链遍历的类型擦除问题

场景背景

在我的C++协程库中,多处需要遍历互相等待的挂起协程链:比如Foo0调用Foo1,Foo1调用Foo2……直至FooN,每个协程都co_await下一个协程的结果,且FooN当前处于挂起状态。这些协程的Promise类型会存储完成时需恢复的awaiter句柄,由此形成一条从FooN到Foo0的单链表。我需要遍历该链表,用于取消后的清理操作,或生成性能分析用的异步栈追踪。

同Promise类型的遍历实现

若所有协程的Promise类型相同,只需持有最后一个协程帧的句柄,就能轻松实现遍历:

void WalkCoroutineChain(std::coroutine_handle<Promise> h) {
  while (h) {
    // ... do something with h ...
    Visit(h);
    
    // Move on to the caller of h's coroutine.
    h = h.promise().awaiter;
  }
}

问题:不同Promise类型的类型擦除需求

但实际场景中,这些协程的Promise类型并不相同:它们共享通用的Promise模板,甚至拥有同一个Promise基类,但由于Promise类型是按返回结果类型模板化的,因此实际类型存在差异。

我需要解决的问题是:给定一个Promise的引用,是否存在符合C++标准的方式,将其存储为void*或std::coroutine_handle<>这类类型擦除形式,同时仍能通过该类型擦除值完成以下两项操作:

  • 恢复或销毁对应的协程;
  • 获取其已知基类的引用(可保证无多继承)。

若能实现,我即可将awaiter成员放入所有Promise都继承的非模板基类中,从而遍历该链表。

推测实现与标准合规性疑问

我推测实际中直接采用以下代码可能可行:

std::coroutine_handle<> type_erased = GetHandleSomehow();
auto base = std::coroutine_handle<PromiseBase>::from_address(type_erased.address());

但这可能属于未定义行为,依据如下:

  • 在C++20草案中,std::coroutine_handle<Promise>::from_address的前置条件仅要求addr来自之前对address的调用,但未说明调用address的对象类型。
  • 在最新草案中,明确要求addr来自对cv coroutine_handle<Promise>类型对象调用address的结果,而若Promise是实际Promise类型的基类,则该条件不满足。

内容的提问来源于stack exchange,提问作者jacobsa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 09:45:31