如何在C++中实现带格式化失败信息的断言?
标准实现方案
C++标准库原生的assert宏仅支持单个条件参数,无法直接传递格式化的失败消息,但可以通过以下标准合规的方式实现你需要的功能:
1. 封装带格式化消息的断言宏(C++20及以上)
利用C++20引入的std::format和std::source_location,可以封装一个支持自定义格式化消息的断言宏,同时保留原生assert在发布版(定义NDEBUG时)自动失效的特性:
#include <cstdio> #include <format> #include <source_location> #include <cstdlib> #ifdef NDEBUG #define my_assert(expr, fmt, ...) ((void)0) #else #define my_assert(expr, fmt, ...) \ do { \ if (!(expr)) { \ const auto msg = std::format(fmt, __VA_ARGS__); \ const auto loc = std::source_location::current(); \ std::fprintf(stderr, "Assertion failed: %s\nFile: %s\nLine: %d\nFunction: %s\nMessage: %s\n", \ #expr, loc.file_name(), loc.line(), loc.function_name(), msg.c_str()); \ std::abort(); \ } \ } while(false) #endif
使用示例:
void func(int a, int b) { my_assert(a == b, "values differ: {} != {}", a, b); }
2. 延迟生成消息的断言宏(性能优化)
如果希望仅在断言失败时才生成格式化消息(避免不必要的字符串处理开销),可以封装一个接受消息生成lambda的版本:
#include <cstdio> #include <source_location> #include <cstdlib> #ifdef NDEBUG #define my_assert_lazy(expr, msg_generator) ((void)0) #else #define my_assert_lazy(expr, msg_generator) \ do { \ if (!(expr)) { \ const auto msg = msg_generator(); \ const auto loc = std::source_location::current(); \ std::fprintf(stderr, "Assertion failed: %s\nFile: %s\nLine: %d\nFunction: %s\nMessage: %s\n", \ #expr, loc.file_name(), loc.line(), loc.function_name(), msg.c_str()); \ std::abort(); \ } \ } while(false) #endif
使用示例:
void func(int a, int b) { my_assert_lazy(a == b, [&](){ return std::format("values differ: {} != {}", a, b); }); }
注意事项
- 上述实现完全基于C++标准特性,无编译器依赖;
- 定义
NDEBUG宏时,断言会被自动禁用,和原生assert行为一致; - 避免在断言消息中包含有副作用的代码(比如
++a),因为发布版中这些代码不会执行。
内容的提问来源于stack exchange,提问作者Konrad Eisele
相关产品推荐
相关产品推荐

