如何合规获取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
相关产品推荐
相关产品推荐

