std::source_location 是 C++20 引入的类型,用于编译期捕获调用点的文件名、行号、函数名和列号,比 __FILE__ 和 __LINE__ 更安全灵活,支持类型安全、重载、模板推导及跨函数位置传递。

std::source_location 是什么,为什么能替代 __FILE__ 和 __LINE__
std::source_location 是 C++20 引入的标准类型,用于在编译期捕获调用点的文件名、行号、函数名和列号。它比宏 __FILE__ 和 __LINE__ 更安全、更灵活:宏展开后是字符串字面量或整数字面量,类型不固定,且无法参与重载或模板推导;而 std::source_location 是一个可拷贝、可传递、可默认构造的结构体,支持隐式构造(编译器自动填入),还能跨函数边界保留位置信息。
常见错误是手动传参:log("msg", std::source_location::current())——这会记录 log 函数内部的位置,而非调用者位置。正确做法是让参数带默认值,由编译器在调用点注入。
如何声明日志函数以自动捕获调用位置
关键在于把 std::source_location 设为带默认值的函数参数,并放在参数列表末尾:
void log(const char* msg, const std::source_location& loc = std::source_location::current()) {
printf("[%s:%d] %s\n", loc.file_name(), loc.line(), msg);
}这样调用时无需显式传参:log("user logged in"),编译器会在每一处调用点自动生成对应位置信息。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 必须用
= std::source_location::current(),不能写成= {}或= std::source_location{},否则得不到调用点信息 - 不能对
loc取地址或绑定到非 const 引用再转发(如f(loc)),否则可能丢失原始位置——应直接传递值或 const 引用 - 如果日志函数是模板或内联函数,依然有效;但若通过函数指针或虚函数调用,则无法自动注入,需显式传入
与宏方案对比:哪些场景下必须用 source_location
当需要类型安全、可组合、可测试的日志接口时,std::source_location 明显优于宏:
- 宏无法被 IDE 正确跳转到调用处(跳转到宏定义);
source_location支持真·调用点导航 - 宏展开后无法做 constexpr 判断(比如按文件路径过滤日志);
loc.file_name()在 constexpr 上下文中可用(C++23 起更完善) - 封装成类成员函数时,宏会暴露实现细节;而
source_location可作为私有参数隐藏,不影响公有接口签名 - 调试器能直接查看
loc的字段值;宏展开后只剩字符串常量,无结构信息
但注意:source_location::function_name() 返回的是编译器生成的符号名(如 "main" 或 "_Z3foov"),不是原始源码中的函数声明名,GCC/Clang 表现一致,MSVC 可能为空。
实际使用中容易忽略的兼容性和性能细节
std::source_location 零开销,所有字段在编译期确定,运行时只是几个字面量拷贝。但它有明确的编译器支持要求:
- GCC 10+、Clang 11+、MSVC 19.29+ 才完整支持
std::source_location::current()的隐式注入 - 低版本编译器会报错“no matching function”,此时需降级为宏 + 条件编译,例如:
#if __cpp_lib_source_location >= 201907L - 静态库中若导出含
source_location参数的函数,调用方和定义方编译器版本不一致可能导致 ABI 不兼容(罕见但存在) - 日志宏仍有必要保留:比如需要记录表达式值(
LOG(x + y)),此时仍得靠宏包裹整个语句,再把source_location作为额外参数传入
最麻烦的其实是跨编译单元的 inline 函数——如果头文件里定义了内联日志函数,而多个 TU 同时包含它,每个 TU 的 current() 仍能正确指向各自调用点,这点很可靠。但别试图把它塞进 lambda 默认捕获里,C++20 不允许。

















