std::source_location是c++20引入的轻量结构体,用于编译期捕获调用点的文件名、函数名、行号和列号;它不自动打印,需手动调用file_name()、line()等成员并格式化输出,否则直接流输出无意义。

std::source_location 是什么,为什么不能直接用
std::source_location 是 C++20 引入的轻量结构体,用于在编译期捕获调用点的文件名、函数名、行号和列号。但它本身不打印——它只存信息。你得手动把它转成字符串再输出,否则 std::cout 会编译失败(没定义 <code>operator)。
常见错误是写成这样:
std::cout <p>原因:标准库没为 <code>std::source_location</code> 提供流输出重载。</p><h3>如何正确获取并打印行号(含文件和函数)</h3><p>最常用方式是调用静态成员函数 <code>std::source_location::current()</code>,它在**调用点**生成位置信息,不是在函数内部声明时生成。所以必须作为默认参数或立即调用:</p>
- 作为函数参数默认值最稳妥,确保捕获的是调用方位置
- 不能在变量初始化里单独写
auto loc = std::source_location::current(),那会固定在定义处(通常是头文件或全局),不是你想要的调用点 - 行号通过
loc.line()获取,类型是unsigned int,不是int
示例:
void log(const char* msg, const std::source_location& loc = std::source_location::current()) {
std::cout <h3>为什么默认参数比宏更可靠</h3><p>有人用 <code>#define LOG(msg) std::cout ,但宏有硬伤:</code></p>
- 无法获取函数名(
__func__是 C99,但宏里拼接易出错) - 不能跨编译单元一致工作(比如模板实例化点可能不是你写的那行)
- 调试器里看不到宏展开后的实际调用位置(IDE 跳转失效)
-
std::source_location在模板中也能正确指向用户调用处,而宏总指向宏定义处
注意:std::source_location::current() 是 constexpr 函数,编译期求值,无运行时开销。
兼容性与编译器要求
不是所有 C++20 实现都完整支持 std::source_location:
- GCC 10+ 支持,但需开启
-std=c++20(-std=gnu++20也行) - Clang 12+ 支持,同样需要 C++20 模式
- MSVC 19.30+(VS 2022 17.0+)支持,但早期版本(如 VS 2019)即使开 C++20 也不支持
- 若编译失败报错
‘source_location’ is not a member of ‘std’,先检查编译器版本和标准开关
没有 fallback 的标准方式;如果必须兼容老编译器,只能条件编译 + 宏回退,但行号精度会下降。
真正容易被忽略的是:std::source_location 的 file_name() 返回 const char*,指向编译器内嵌字符串字面量,生命周期永久,但内容依赖编译器实现——某些嵌入式工具链可能返回空或相对路径,别假设它总是绝对路径。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











