std::source_location::function_name() 不含命名空间,因其实现依赖编译器提供的未修饰短名,且标准规定其为 implementation-defined;可靠获取完整签名需用 __pretty_function__(gcc/clang)或 __funcsig__(msvc)宏。

std::source_location 本身不提供函数签名或命名空间信息——它只记录调用点的文件、行号、函数名(通常是编译器生成的简略名,如 "foo" 而非 "ns::MyClass::bar"),且该函数名字段在标准中明确是“implementation-defined”,不可靠。
为什么 std::source_location::function_name() 通常不带命名空间
这是编译器实现决定的:function_name() 返回的是编译器在调用点能“方便拿到”的符号名,GCC/Clang 默认返回未修饰(unmangled)的短名(甚至可能为空),MSVC 略好但也不保证含命名空间。它不是为反射设计的,本质是调试辅助字段。
- 即使启用
-frecord-gcc-switches或/Zi,也不会改变function_name()的内容 - 模板实例化点、lambda、内联函数的返回值更不可预测
- 不能依赖它做日志分类或符号解析——它连是否以
const char*结尾都不保证(C++23 要求是 null-terminated,但之前版本不强制)
要打印完整签名,必须结合 __PRETTY_FUNCTION__ 或 __FUNCSIG__
这两个预定义宏由编译器扩展提供,内容稳定、含命名空间、类作用域、模板参数和调用约定(尤其 __PRETTY_FUNCTION__ 在 GCC/Clang,__FUNCSIG__ 在 MSVC)。它们不是标准 C++,但所有主流编译器都支持,且比 source_location::function_name() 可靠得多。
-
__PRETTY_FUNCTION__(GCC/Clang):返回可读字符串,如"static void ns::Logger::log(const char*, int) [with T = double]" -
__FUNCSIG__(MSVC):返回完整签名,含__cdecl等调用约定,如"void __cdecl ns::Logger::log<double>(const char *,int)"</double> - 它们在宏展开时求值,所以必须在目标函数体内使用,不能从
source_location里“提取”
安全封装:用宏桥接 source_location 和编译器宏
把 source_location::current() 和 __PRETTY_FUNCTION__ 绑定到同一处,避免手写重复。注意宏参数顺序和逗号表达式陷阱:
#define LOG_HERE() do { \
auto loc = std::source_location::current(); \
std::cerr
- 不要试图把
__PRETTY_FUNCTION__存进std::source_location对象——它没有字段容纳这个 - 若需运行时获取(比如通用日志函数),必须把
__PRETTY_FUNCTION__作为额外参数传入,例如:log_debug("msg", __PRETTY_FUNCTION__, std::source_location::current()) - Clang 的
__FUNCSIG__比__PRETTY_FUNCTION__更全(含返回类型),但可读性略差;GCC 不支持__FUNCSIG__
真正需要完整签名时,别碰 source_location::function_name()。它就像一个带刻度但没数字的表盘——看着像能读数,其实只能估个大概。命名空间、模板实参、重载区分,全得靠编译器宏兜底。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











