std::source_location是C++20引入的编译期源码位置捕获设施,提供file_name()、function_name()、line()、column()等只读接口,通过default参数std::source_location::current()自动填充调用点信息,类型安全且不依赖宏。

std::source_location 是 C++20 引入的标准设施,用于在编译期捕获调用点的源码位置信息(文件名、函数名、行号、列号),常用于日志、断言、调试和诊断工具中。它不依赖宏(如 __FILE__、__LINE__),而是通过编译器自动推导,类型安全且可作为函数参数默认构造。
基本用法:作为函数参数自动填充
最常见方式是将 std::source_location 作为函数最后一个参数,并赋予默认值 std::source_location::current()。编译器会在每次调用处自动填入该调用点的位置信息:
示例:
#include#include void log(const char* msg, const std::source_location& loc = std::source_location::current()) { std::cout << "[" << loc.file_name() << ":" << loc.line() << " in " << loc.function_name() << "] " << msg << '\n'; }
int main() { log("Hello from main"); // 输出类似:[main.cpp:12 in main] Hello from main return 0; }
注意:loc 的默认值由编译器在调用点生成,不是在函数定义处求值 —— 所以每个调用都反映真实调用位置。
关键成员函数说明
std::source_location 提供以下只读访问接口:
-
file_name():返回const char*,通常是绝对或相对路径(取决于编译器和构建配置) -
function_name():返回调用点所在函数的签名(如"int main()"或"void foo()"),非标准化,但通常可用 -
line():返回调用语句所在的行号(unsigned int) -
column():返回列号(从 1 开始),支持度因编译器而异(GCC/Clang 一般支持,MSVC 较新版本支持)
使用注意事项与限制
这个类型设计为轻量、不可变、仅编译期生成,因此有几点需留意:
- 不能手动构造完整信息(如不能写
source_location{"a.cpp", 42, 1}),只能通过current()获取调用点快照 - 不参与运行时反射;函数名和文件路径是字面量字符串,存储在只读段,无动态解析开销
- 若函数被内联,
current()仍指向原始调用点,不是内联后展开的位置(这是预期行为) - 跨编译单元调用也准确 —— 编译器保证每个调用站点独立生成位置信息
进阶技巧:封装日志宏或模板辅助
虽然 std::source_location 本身不依赖宏,但有时需配合宏隐藏参数传递(例如统一日志入口):
#define LOG(msg) log(msg, std::source_location::current())// 使用时无需显式传参 LOG("User login failed"); // 自动捕获此处位置
也可结合模板实现泛型日志器,避免重复声明默认参数:
templatevoid debug_log(const char* fmt, Args&&... args) { auto loc = std::source_location::current(); // 使用 fmt + args 做格式化(如用 std::format 或 spdlog) std::printf("[%s:%u] ", loc.file_name(), loc.line()); // ... 实际格式化逻辑 }
不复杂但容易忽略:它让“哪里出的问题”这件事,第一次真正进入了标准库的类型系统。











