最常用写法是定义宏LOG_LINE()调用std::source_location::current(),日志函数按值接收默认参数;不可取地址或绑定引用,因返回纯右值;跨平台需校验line()==1且file_name()为空时回退。

std::source_location 本身不支持直接打印,必须显式调用 line()、file_name() 等成员函数才能拿到行号等信息;它只是个轻量值类型,不是格式化工具。
怎么在日志里自动捕获当前行号和文件名
最常用写法是定义一个宏,把 std::source_location::current() 的调用“固定”在调用点展开:
#define LOG_LINE() std::source_location::current()
然后在日志函数中接收该参数(默认值避免每个调用都手动传):
void log(const char* msg, std::source_location loc = std::source_location::current()) {
printf("[%s:%d] %s\n", loc.file_name(), loc.line(), msg);
}调用时直接 log("user logged in") 就能打出真实调用处的行号——因为宏没参与,std::source_location::current() 是在调用点编译期求值的。
立即学习“C++免费学习笔记(深入)”;
为什么不能直接传 &std::source_location::current()
常见错误是试图取地址或绑定引用:
-
auto& loc = std::source_location::current();—— 错,返回的是纯右值,引用绑定失败(GCC/Clang 报错cannot bind non-const lvalue reference to an rvalue) -
const auto& loc = ...—— 虽然语法通过,但会延长临时对象生命周期,行为不可靠;不同编译器优化下可能捕获到宏展开位置而非真实调用点 - 正确做法永远是按值传递
std::source_location,它只有 4 个size_t成员,开销极小
MSVC、GCC、Clang 对 __builtin_SOURCE_LOCATION 的兼容差异
C++20 标准接口统一,但底层实现依赖编译器扩展:
- Clang/GCC:基于
__builtin_SOURCE_LOCATION,需开启-std=c++20且不加-fno-builtin - MSVC:从 19.30(VS 2022 17.0)起原生支持,但旧版(如 VS 2019)即使开 C++20 也不支持,会静默回退为默认构造值(
line() == 1,file_name() == "") - 跨平台项目建议加运行时校验:
if (loc.line() == 1 && std::string_view(loc.file_name()).empty()) { /* fallback */ }
注意:std::source_location::current() 的值完全由编译器在翻译单元内填充,无法被宏、内联函数或模板推导干扰——但如果你把它藏在中间函数里(比如封装一层再转发),那拿到的就是那一层的行号,不是原始调用点。想保真,就得让 current() 出现在最终日志调用的同一行。这是最容易忽略、也最难调试的点。











