如何自动获取C++协程函数名称以实现协程追踪器?
C++协程自动获取函数名实现方案
核心思路
标准C++的std::coroutine_handle本身不携带函数名信息,但可以通过协程的promise_type间接实现自动捕获:在promise的初始化阶段(协程函数执行初期),利用编译器宏捕获当前协程函数的名字并存储,后续通过coroutine_handle获取promise对象即可拿到函数名,全程无需用户手动传递宏。
具体实现
以下是兼容GCC/Clang/MSVC等主流编译器的完整可运行示例:
1. 定义TTask与Promise类型
#include <coroutine> #include <string> #include <iostream> template<typename T> struct TTask; // 协程Promise类型,负责存储函数名和执行结果 template<typename T> struct TTaskPromise { T result_; std::string func_name_; // 生成返回对象时自动捕获当前协程函数名 TTask<T> get_return_object() { // __FUNCTION__为编译器扩展,返回完整函数名(含类名若为成员函数) // 若需严格遵循标准C++,可替换为__func__(仅返回短函数名) func_name_ = __FUNCTION__; return TTask<T>{std::coroutine_handle<TTaskPromise>::from_promise(*this)}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void return_value(T value) { result_ = value; } void unhandled_exception() { std::terminate(); } }; // 协程任务类型,持有协程句柄并提供函数名获取接口 template<typename T> struct TTask { using promise_type = TTaskPromise<T>; std::coroutine_handle<promise_type> handle_; explicit TTask(std::coroutine_handle<promise_type> handle) : handle_(handle) {} ~TTask() { if (handle_) handle_.destroy(); } // 获取协程函数名 [[nodiscard]] std::string get_func_name() const { return handle_.promise().func_name_; } // 执行协程并获取结果 T get_result() { handle_.resume(); return handle_.promise().result_; } };
2. 模拟Wait协程等待器
// 模拟协程等待操作 auto Wait(double) { struct Awaiter { bool await_ready() const { return false; } void await_suspend(std::coroutine_handle<>) {} void await_resume() {} }; return Awaiter{}; }
3. 测试协程与追踪逻辑
// 目标协程函数,无需手动传递任何函数名相关宏 TTask<float> CoroFunc() { co_await Wait(1.0); co_return 1.0f; } int main() { auto task = CoroFunc(); // 输出协程函数名:CoroFunc std::cout << "协程启动,函数名:" << task.get_func_name() << std::endl; float result = task.get_result(); std::cout << "协程结束,结果:" << result << std::endl; return 0; }
关键说明
- 编译器宏兼容性:
__FUNCTION__是主流编译器均支持的扩展宏,若需严格遵循标准C++,可替换为__func__(仅返回短函数名,不含类名等前缀)。 - 自动捕获原理:
get_return_object是协程启动后第一个被调用的promise方法,此时处于协程函数的执行上下文,__FUNCTION__自然指向当前协程函数名,无需用户手动干预。 - 扩展追踪场景:若需追踪协程的启动、恢复、结束状态,可在promise的
initial_suspend、final_suspend、await_suspend等方法中添加日志逻辑,结合存储的函数名即可实现完整状态追踪。
内容的提问来源于stack exchange,提问作者Artem Selivanov
相关产品推荐
相关产品推荐

