c++oding="utf-8" ?>
std::source_location 是 c++20 引入的类型安全源位置设施,比 file 和 line 更可靠:它在调用点捕获文件、函数、行号、列号,避免宏在内联或封装中记录错误位置,且必须作为带默认值的函数参数传入以确保准确性。

std::source_location 是什么,为什么它比 __FILE__ 和 __LINE__ 更好
std::source_location 是 C++20 引入的标准设施,用于在编译期捕获调用点的源码位置(文件、函数、行号、列号)。它不是宏,而是类型安全的结构体,能避免 __FILE__ / __LINE__ 在宏展开或内联函数中“错位”的问题——比如你把日志封装成 inline 函数,传统宏会记录该 inline 函数内部的行号,而 std::source_location::current() 默认捕获的是**调用处**的位置。
关键点:它必须作为函数参数(通常用默认值)传入,不能靠宏“注入”,否则就失去意义。
如何写一个带 source_location 的日志函数
最简可用的日志辅助函数长这样:
void debug_log(const char* msg, const std::source_location loc = std::source_location::current()) {
std::cerr <p>调用时完全不用传参:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><pre class="brush:php;toolbar:false;">int main() {
debug_log("starting up"); // 输出类似:[main.cpp:5 in main] starting up
return 0;
}常见错误:
- 把
std::source_location::current()写在函数体内(比如在函数开头手动调用),那记录的就是函数定义处的行号,不是调用点 - 参数没设默认值,又忘记传 —— 编译直接报错,因为
std::source_location没有默认构造函数 - 用
const std::source_location&而非值传递:虽然可行,但没必要;它是个小结构(通常 4 个size_t),按值传更清晰,且避免 lifetime 问题
支持格式化字符串和可变参数的进阶写法
想兼容 printf 风格(如 debug_log("value = %d", x)),得用 C++20 的 std::format:
template<typename... args>
void debug_log(std::string_view fmt, Args&&... args) {
auto loc = std::source_location::current();
std::cerr <p>注意点:</p>
<ul>
<li>必须用 <code>std::string_view</code> 接收格式串,否则 <code>std::vformat</code> 无法推导</li>
<li>需要编译器开启 C++20(<code>-std=c++20</code>)且标准库支持 <code>std::format</code>(GCC 13+、Clang 15+、MSVC 19.30+)</li>
<li>如果目标环境不支持 <code>std::format</code>,退回到 <code>fmt::format</code>(需链接 {fmt} 库)或用 <code>std::ostringstream</code> 拼接,但会丢失类型安全</li>
</ul>
<h3>编译与兼容性陷阱</h3>
<p>即使写了 C++20 代码,也可能得不到正确行号:</p>
<ul>
<li>某些旧版 libc++(如 macOS 自带)未完全实现 <code>std::source_location</code>,<code>file_name()</code> 可能返回空串或 "<code>???</code>" —— 建议用 <code>clang++ -stdlib=libc++</code> + 升级 libc++,或切到 libstdc++</li>
<li>启用 LTO(<code>-flto</code>)时,部分编译器可能优化掉位置信息(尤其在 Release 模式下);调试信息本身不受影响,但 <code>source_location</code> 是编译期常量,LTO 理论上不该动它,实际表现因编译器版本而异</li>
<li>Windows 上 MSVC 对 <code>function_name()</code> 返回的是修饰名(mangled name),不是可读函数名;若需可读名,得额外调用 <code>UnDecorateSymbolName</code>,代价高,一般只在诊断工具里做</li>
</ul>
<p>最稳的做法:开发阶段用 <code>-O0 -g -std=c++20</code>,确保 <code>source_location</code> 行为可预测;上线前若关调试信息,至少保留 <code>file_name()</code> 和 <code>line()</code>,它们不依赖 debug info。</p></typename...>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










