std::source_location是c++20引入的标准库类型,用于在编译期捕获调用点的文件名、行号、函数名和列号;它比__file__和__line__更安全、可传递、可存储,且内联后仍指向原始调用位置。

std::source_location 是什么,为什么能替代 __FILE__ 和 __LINE__
它不是宏,而是一个标准库类型(C++20 引入),在编译期捕获调用点的文件名、行号、函数名和列号。相比 __FILE__ 和 __LINE__ 这类预处理宏,std::source_location 更安全、可传递、可存储,且能被优化器更好处理——比如内联后仍指向原始调用位置,而不是内联展开后的文件/行。
关键点:它默认构造时自动捕获**调用点**信息,不是定义点。所以必须作为函数参数(通常带默认值)传入,不能直接写 std::source_location::current() 在全局或静态上下文中——那会捕获该语句所在位置,而非使用者期望的位置。
怎么写一个带 source_location 的日志函数
最典型用法是封装日志或断言,让调用者无需手动传参:
- 参数声明为
const std::source_location& loc = std::source_location::current() - 函数体里直接用
loc.file_name()、loc.line()、loc.function_name() - 注意:
file_name()返回const char*,不是std::string;内容生命周期由编译器保证,但别存指针长期使用
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);
}
// 调用时完全不用提 loc
log("connection failed"); // 自动捕获调用处的文件和行
__FILE__ 和 __LINE__ 无法做到的事,source_location 可以
预处理宏是纯文本替换,无法参与类型系统或运行时逻辑;std::source_location 是完整对象,支持:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 作为类成员保存(例如错误对象里存触发位置):
struct Error { std::source_location loc; }; - 跨函数传递(比如从入口函数传给校验函数):
check_value(x, std::source_location::current()); - 配合模板推导做更精细的诊断(如结合
static_assert消息) - 获取列号:
loc.column(),这是__LINE__完全没有的
但注意:function_name() 内容不标准化(MSVC 返回修饰名,GCC/Clang 返回未修饰名),不建议用于逻辑判断,只适合展示。
容易踩的坑:默认参数 + 内联 + 模板
看似简单,但几个组合会让行为出人意料:
- 如果函数被
inline或模板实例化,std::source_location::current()仍指向**调用点**,不是定义点——这是设计目标,但有人误以为会被内联“污染” - 不要在头文件里对
std::source_location::current()做 constexpr 初始化(比如constexpr auto loc = std::source_location::current();),这非法:它不是常量表达式 - 避免在 lambda 捕获列表里直接写
[loc = std::source_location::current()]——那捕获的是定义 lambda 的位置,不是调用 lambda 的位置;真要捕获调用点,得把loc作为 lambda 参数传入
最稳妥的习惯:只在函数参数里用默认值,其他地方一律显式传入 std::source_location::current()。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










