std::source_location 是 c++20 引入的类型安全、可传递的源码位置捕获机制,替代 __file__ 和 __line__ 宏;它通过编译器隐式构造,需作为默认参数传递或在宏中透传以确保记录调用点而非定义点。

std::source_location 是什么,为什么能替代 __FILE__ 和 __LINE__
std::source_location 是 C++20 引入的标准设施,用于在编译期捕获调用点的源码位置(文件、函数、行号、列号)。它比宏 __FILE__ 和 __LINE__ 更类型安全、可传递、可拷贝,且支持自定义日志函数签名。关键在于:它不是宏展开,而是由编译器在调用处隐式构造的 std::source_location 对象。
常见错误是直接写 std::source_location::current() 在日志函数内部——这会记录日志函数自身的定义位置,而非调用它的那行代码。
正确做法是让日志函数接收一个默认参数:
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);
}
如何在日志宏中保留 source_location 的调用点语义
纯函数方式虽好,但很多项目仍依赖宏做轻量级日志开关(如 LOG_INFO("x = %d", x))。这时不能直接把 std::source_location::current() 放进宏体里——因为宏展开后,current() 会在宏定义处求值,而非调用处。
必须用宏把调用点信息“透传”给底层函数:
- 宏内调用
std::source_location::current(),确保它在宏展开位置执行 - 宏再将该值作为参数转发给实际日志函数
- 避免在宏里拼接字符串或做复杂格式化,否则可能干扰
source_location的捕获时机
示例:
#define LOG(msg, ...) \
do { \
log_impl((msg), ##__VA_ARGS__, std::source_location::current()); \
} while(0)
<p>void log_impl(const char* fmt, ..., std::source_location loc = std::source_location::current());</p>
std::source_location 在不同编译器下的行为差异
虽然标准规定 std::source_location::current() 应返回调用点信息,但实际表现依赖编译器实现和优化级别:
-
clang 14+和gcc 12+基本可靠,但-O2可能导致内联后位置偏移(尤其函数被强制内联时) -
MSVC 19.30+支持良好,但需启用/std:c++20,且/Zi或/Z7调试信息会影响file_name()返回完整路径还是相对路径 -
file_name()返回的是编译器看到的路径(可能是绝对路径、相对路径,或经过-fmacro-prefix-map重映射后的路径),不保证与源码树一致 -
function_name()在 GCC/Clang 下通常返回 mangled 名,MSVC 返回较可读名;若需可读函数名,建议配合abi::__cxa_demangle或平台 API
性能开销和生产环境注意事项
std::source_location 本身是 POD 类型,构造零成本(无函数调用、无内存分配),但 file_name() 和 function_name() 返回的是 const char*,指向只读段数据,不涉及堆操作。
真正影响性能的是日志输出本身(如 printf、磁盘 I/O、锁竞争),而非 source_location 的使用。但要注意:
- 不要在热循环里高频调用带
source_location的日志函数——不是因为它慢,而是日志本身不该出现在热点路径 - 避免在
constexpr上下文中误用std::source_location::current()(它不是 constexpr 函数) - 如果构建系统用了 ccache 或 distcc,
file_name()可能返回缓存服务器上的路径,需确认构建环境一致性
最易被忽略的一点:std::source_location 不提供列号(column())的稳定语义,GCC 和 Clang 实现为 1,MSVC 未实现该接口,别依赖它做精确定位。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











