C++26:一个用户友好的 assert() 宏
C++26: A User-Friednly assert() macro

原始链接: https://www.sandordargo.com/blog/2026/03/25/cpp26-user-friendly-assert

## C++26 与改进的 `assert()` 即将到来的 C++26 标准旨在改进常用的 `assert()` 宏,解决一个长期存在的缺陷。虽然看似简单,但 `assert()` 是一个宏,在使用模板或花括号初始化等现代 C++ 特性时,容易出现意外的编译错误。这是因为预处理器对 C++ 语法的理解有限,导致它错误地解释断言中的逗号和花括号。虽然存在解决方法(添加额外的括号),但它们既笨拙又容易出错。 P2264R7 建议将 `assert()` 重定义为可变参数宏,直接接受参数,而无需单个包含表达式。这个简单的更改解决了编译问题,而不会破坏现有代码。诊断消息现在需要 `&&` 运算符以提高清晰度,防止意外的始终为真断言。 尽管未来将有契约(contracts)的出现,`assert()` 仍然将是运行时验证的宝贵工具。这次更新不是关于替换 `assert()`,而是使其更健壮和用户友好——这是有益的、渐进的语言演化的一个很好的例子。虽然截至 2026 年 2 月,主要编译器尚未实现此更改,但此更改有望为所有 C++ 开发者提供更流畅的体验。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 C++26: 一个用户友好的 assert() 宏 (sandordargo.com) 14 分,jandeboevrie 1小时前 | 隐藏 | 过去 | 收藏 | 1 条评论 帮助 nyc_pizzadev 12分钟前 | 下一个 [–] assert() 的好处在于你可以自定义:https://github.com/fiberfs/fiberfs/blob/7e79eaabbb180b0f1a79... 在这种情况下,能够看到触发断言的实际值更有帮助。回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

C++26 is bringing some long-overdue changes to assert(). But why are those changes needed? And when do we actually use assert, anyway?

At its core, assert() exists to validate runtime conditions. If the given expression evaluates to false, the program aborts. I’m almost certain you’ve used it before — at work, in personal projects, or at the very least in examples and code snippets.

So what’s the problem?

The macro nobody treats like a macro

assert() is a macro — and a slightly sneaky one at that. Its name is written in lowercase, so it doesn’t follow the usual SCREAMING_SNAKE_CASE convention we associate with macros. There’s a good chance you’ve been using it for years without ever thinking about its macro nature.

Macros, of course, aren’t particularly popular among modern C++ developers. But the issue here isn’t the usual - but valid - “macros are evil” argument. The real problem is more specific:

The preprocessor only understands parentheses for grouping. It does not understand other C++ syntax such as template angle brackets or brace-initialization.

As a result, several otherwise perfectly valid-looking assertions fail to compile:

1
2
3
4
5
6
7
// https://godbolt.org/z/9sqM7PvWh
using Int = int;
int x = 1, y = 2;

assert(std::is_same<int, Int>::value);
assert([x, y]() { return x < y; }() == 1);
assert(std::vector<int>{1, 2, 3}.size() == 3);

Each of these breaks for essentially the same reason: the macro argument parsing gets confused by commas or braces that aren’t wrapped in an extra pair of parentheses.

You can fix each of them, of course, by adding an extra pair of parentheses. For example the last assertion would become assert((std::vector<int>{1, 2, 3}.size() == 3)); - you can play with the examples here.

But let’s be honest: this is ugly, easy to forget, and not exactly beginner-friendly. Sure, after hitting the problem once or twice, most people internalize the workaround — just like with the most vexing parse. Still, it’s unnecessary friction for such a fundamental utility.

P2264R7: Making assert less fragile

This is where Peter Sommerlad’s proposal, P2264R7, comes in.

The proposal fixes the assert macro by redefining it as a variadic macro using __VA_ARGS__. Instead of accepting a single parenthesized expression, assert now takes (...) as its parameter. That small change makes all the previously broken examples just work — no extra parentheses required.

What about diagnostic messages?

Originally, the proposal allowed users to attach diagnostic text via the comma operator, similar to static_assert. That idea didn’t survive the review phase.

Instead, there is a mechanism to prevent the use of the comma operator on a top level, so you cannot accidentally create always true assertions like this:

1
assert(x > 0 , "x was not greater than zero");

Something that you could very easily create from an existing static_assert.

So if we want to have some diagnostics, we still have to use the && operator instead:

1
assert(x > 0 && "x was not greater than zero");

This keeps the semantics clear and avoids subtle bugs.

But aren’t contracts coming?

One common objection addressed in the proposal is the claim that assert is obsolete in a future with contracts.

Contracts will be great. But they won’t make assert disappear overnight.

Just as concepts didn’t eliminate SFINAE or older template techniques — they simply gave us better tools — contracts won’t erase assert either. Assertions will continue to exist in real-world codebases, whether directly or wrapped inside higher-level precondition utilities. Improving assert is still valuable, especially when the changes are small, simple, and easy to backport.

If you’re curious, the paper discusses several other potential concerns in detail; you can find them in the section on potential liabilities of the proposed change.

Compatibility and availability

Importantly, this change does not break existing code. All previously valid usage patterns remain valid — the proposal merely enables new, less fragile ones.

At the time of writing, (February 2026), none of the major compilers support this feature yet. As with many C++26 improvements, it will take some time before it becomes widely available.

Conclusion

The C++26 update to assert() is a great example of incremental language evolution done right. It doesn’t reinvent assertions, replace them with something flashier, or force new programming models on existing code. Instead, it quietly removes a long-standing sharp edge.

By making assert variadic, the language eliminates a class of surprising compilation failures, improves readability, and reduces the cognitive overhead of using a tool that every C++ developer relies on. It’s a small change — but one that makes everyday C++ just a little bit nicer to work with.

Sometimes, that’s exactly the kind of progress we need.

Connect deeper

If you liked this article, please

联系我们 contact @ memedata.com