c++oding="utf-8" ?>
std::source_location在assert宏中不能直接使用,因为其current()是运行时调用,而宏展开发生在预处理阶段,不支持函数调用;且断言失败才需记录位置,非每次求值都触发。

std::source_location在assert宏里为什么不能直接用
因为std::source_location::current()是运行时调用,而传统assert宏展开发生在预处理阶段,宏参数不支持函数调用——你写assert(x > 0 && std::source_location::current())会编译失败,而且语义也不对:断言失败才该记录位置,不是每次求值都触发。
自己实现带位置信息的断言宏
核心是用__FILE__、__LINE__、__func__(或C++20的std::source_location)在宏展开时捕获上下文。C++20起推荐用std::source_location,它比宏更类型安全、可扩展,且能额外拿到column和file_name完整路径。
实操建议:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 定义宏时用
std::source_location::current()作为默认参数,避免手动传参出错 - 不要在宏体内直接调用
std::source_location::current()两次——它可能返回不同实例(虽然通常不会),应只调一次并存为变量 - 确保编译器支持C++20且启用了
-std=c++20(GCC 10+/Clang 11+/MSVC 19.30+) - 若需兼容旧标准,可用宏检测:
#if __cpp_lib_source_location >= 201907L
示例:
#define MY_ASSERT(expr) \
do { \
if (!(expr)) { \
const auto loc = std::source_location::current(); \
std::cerr
<h3>std::source_location::current()的调用时机和开销</h3>
<p>它不是魔法——底层仍依赖编译器内建支持(如GCC的<code>__builtin_SOURCE_LOCATION</code>),生成的是常量数据,**零运行时开销**。但要注意:</p>
- 必须在函数作用域内调用,不能在全局/命名空间作用域(否则报错:
std::source_location::current() must be called from inside a function) - 在模板函数或constexpr上下文中调用是合法的,但
file_name()等成员函数返回const char*,非字面量,不能用于static_assert - 某些嵌入式或裁剪版STL可能未实现该特性(如libc++ 12之前版本需手动启用)
和传统assert共存与日志集成
别直接替换assert——系统级断言(如NDEBUG下消失)和自定义断言用途不同。推荐分层:
-
assert保留给开发期快速崩溃,依赖NDEBUG控制 -
MY_ASSERT用于需要稳定记录位置的场景(如测试框架、关键路径校验),不受NDEBUG影响 - 若要输出到日志系统,把
std::cerr换成你的日志器调用,并传入loc结构体,避免重复解析__FILE__等宏
容易被忽略的一点:std::source_location的file_name()返回的是绝对路径还是相对路径,取决于编译器和构建系统(如CMake的set(CMAKE_CXX_STANDARD 20)本身不影响,但add_compile_options(-frecord-gcc-switches)之类可能干扰),调试时最好先打印验证。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










