

新闻资讯
技术学院std::source_location 是 C++20 引入的标准设施,用于在编译期捕获调用点的源码位置信息。它不是宏,而是一个轻量值类型,包含 file_name()、line()、column() 和 function_name() 四个只读访问函数。它不能直接替代 __FILE__ 和 __LINE__ 的宏展开行为——因为 std::source_location::current() 是一个函数调用,其返回值反映的是该函数被调用处的位置,而非宏定义处。
常见误用是把它写*局变量或静态常量初始化:
static const auto loc = std::source_location::current(); // ❌ 错!总指向这行
正确做法是让它作为函数参数默认值,在每次调用时自动注入实际调用点信息。
最典型用途是为日志、断言、调试工具注入上下文。关键在于把 std::source_location 设为带默认值的函数参数:
std::source_location::current(),不能加括号以外的任何表达式(如 std::source_location{} 会固定为定义处)示例:
void log(const char* msg, std::source_location loc = std::source_location::current()) {
fprintf(stderr, "[%s:%d] %s\n", loc.file_name(), loc.line(), msg);
}
// 调用方完全无感知:
log("buffer overflow"); // 自动捕获这一行的文件和行号function_name() 返回的是编译器生成的符号名(mangled name),标准只要求它“尽可能描述调用点所在函数”,不保证可读性或跨编译器一致。GCC 可能返回 "void foo()",Clang 可能返回 "foo",MSVC 可能返回 。
如果你需要稳定可读的函数名:
function_name() 做逻辑判断(比如 switch 或 if 比较)std::source_location 和 assert 没有直接集成,C++23 才引入 std::assertion_handler 支持自定义断言处理,但目前主流标准库(libstdc++、libc++、MSVC STL)的 assert 仍基于传统宏,输出由预处理器决定。
你可以自己封装断言宏来桥接:
#define MY_ASSERT(x) do { \
if (!(x)) { \
log_assert(#x, std::source_location::current()); \
std::abort(); \
} \
} while(0)
void log_assert(const char* expr, std::source_location loc) {
fprintf(stderr, "Assertion failed: %s at %s:%d\n", expr, loc.file_name(), loc.line());
}
注意:宏里调用 std::source_location::current() 是安全的,因为宏展开后它出现在调用点,不是宏定义内部。
真正容易被忽略的是:std::source 在 constexpr 函数中无法使用
_locationcurrent()(编译期无法确定“调用点”),所以它只适用于运行时上下文;另外,某些嵌入式或 freestanding 环境可能未实现该特性,需检查 __cpp_lib_source_location 宏。