如何通过类似lock_guard的方式自动记录函数进出的source_location信息?
解决方案
方案一:RAII守卫类(无需修改return语句)
如果可以接受logExit输出的行号为函数入口的行号,那么可以用RAII类实现类似lock_guard的单行用法:
#include <source_location> #include <iostream> using namespace std; void logEnter(const source_location location = source_location::current()){ cout << "Log, entering " << location.function_name() <<" at line "<< location.line() << endl; } void logExit(const source_location location = source_location::current()){ cout << "Log, exiting " << location.function_name() <<" at line "<< location.line() << endl; } // RAII守卫类 class LogGuard { public: explicit LogGuard(const source_location loc = source_location::current()) : loc_(loc) { logEnter(loc_); } ~LogGuard() { logExit(loc_); } // 禁止拷贝和移动,避免意外复制 LogGuard(const LogGuard&) = delete; LogGuard& operator=(const LogGuard&) = delete; private: source_location loc_; }; // 使用示例 string parity(int x) { LogGuard guard; // 只需这一行 if (x%2 == 0) return "even"; return "odd"; }
调用parity(3)时,输出为:
Log, entering parity at line 26 Log, exiting parity at line 26
这种方案的优点是完全不用修改现有函数里的return语句,代码改动极小;缺点是logExit的行号和logEnter一致,无法追踪到具体是哪个return触发的退出。
方案二:宏替换return(保留return行号)
如果需要logExit输出对应return语句的行号,可以用宏替换原有的return关键字,自动插入logExit调用:
#include <source_location> #include <iostream> using namespace std; void logEnter(const source_location location = source_location::current()){ cout << "Log, entering " << location.function_name() <<" at line "<< location.line() << endl; } void logExit(const source_location location = source_location::current()){ cout << "Log, exiting " << location.function_name() <<" at line "<< location.line() << endl; } // 定义宏替换return #define RETURN(val) do { logExit(); return val; } while(0) // 使用示例 string parity(int x) { logEnter(); // 进入日志 if (x%2 == 0) RETURN("even"); // 替换原return RETURN("odd"); }
调用parity(3)时,输出和你期望的一致:
Log, entering parity at line 18 Log, exiting parity at line 21
这种方案的优点是能保留return语句的行号;缺点是需要将函数里所有的return替换为RETURN宏,改动量略大于RAII方案,但仍然是批量替换级别的操作,适合大量函数的场景。
内容的提问来源于stack exchange,提问作者raphchar
相关产品推荐
相关产品推荐

