53 comments

[ 3.3 ms ] story [ 72.6 ms ] thread
Biggest open question is whether the small changes to the module system in this standard will actually lead to more widespread adoption
This is awesome. I've was a dev on the C++ team at MS in the 90s and was sure that RTTI was the closest the language would ever get to having a true reflection system.
I look forwards to getting to make use of this in 2040!

Proper reflection is exciting.

Finally, reflection has arrived, five years after I last touched a line in c++. I wonder how long would it take the committee, if ever, to introduce destructing move.
What do you mean by a destructing move? Are you trying to avoid use of a moved object after you've moved it?

eg. B = std::move(A); // You are worried about touching A when it's in this indeterminate state?

C++26 adds destructive moves. They are called relocatable types.

There are edge cases where destructive moves are not safe and it is impossible for the compiler to know they aren't safe. C++ uses non-destructive moves when it can't prove the safety of destructive moves, even if destructive moves may in fact be safe. C++26 adds a type annotation that guarantees destructive moves are safe in cases where you can't prove they are un-safe.

The concept of relocatable types is actually a bit broader in scope than just destructive moves, but destructive moves are one of the things it enables. It is a welcome change.

Great. C++20 has been my favorite and I was wasn't sure what the standards says since it's been a while. I'll be reading the C++26 standard soon
I am somewhat dismayed that contracts were accepted. It feels like piling on ever more complexity to a language which has already surpassed its complexity budget, and given that the feature comes with its own set of footguns I'm not sure that it is justified.

Here's a quote from Bjarne,

> So go back about one year, and we could vote about it before it got into the standard, and some of us voted no. Now we have a much harder problem. This is part of the standard proposal. Do we vote against the standard because there is a feature we think is bad? Because I think this one is bad. And that is a much harder problem. People vote yes because they think: "Oh we are getting a lot of good things out of this.", and they are right. We are also getting a lot of complexity and a lot of bad things. And this proposal, in my opinion is bloated committee design and also incomplete.

Geez if Bjarne thinks it's

> bloated committee design and also incomplete

That's truly in that backdoor alley catching fire

I wonder if C++ already has so much complexity, that it would actually be a good idea to ignore feature creep, and implement any feature with even the most remote use-case.

It sounds (and probably is) insane. But if a feature breaks backwards compatibility, or can't be implemented in a way that non-negligibly affects compiler/IDE performance for codebases that ignore it, what's the issue? Specifically, what significant new issues would it cause that C++’s existing bloat hasn’t?

C++20 isn't fully implemented in any one compiler (https://en.cppreference.com/w/cpp/compiler_support.html#C.2B...).

Contracts are already informally a thing: most functions have preconditions, and if you break those preconditions, the function doesn't make any guarantees of what it does.

We already have some primitive ways to define preconditions, notably the assert macro and the 'restrict' qualifier.

I don't mind a more structured way to define preconditions which can automatically serve as both documentation and debug invariant checks. Though you could argue that a simpler approach would be to "standardize" a convention to use assert() more liberally in the beginning of functions as precondition checks; that a sequence of 'assert's before non-'assert' code should semantically be treated as the functions preconditions by documentation generators etc.

I haven't looked too deep into the design of the actual final contracts feature, maybe it's bad for reasons which have nothing to do with the fundamental idea.

> I am somewhat dismayed that contracts were accepted. It feels like piling on ever more complexity to a language which has already surpassed its complexity budget, and given that the feature comes with its own set of footguns I'm not sure that it is justified.

I don't think this opinion is well informed. Contracts are a killer feature that allows implementing static code analysis that covers error handling and verifiable correct state. This comes for free in components you consume in your code.

https://herbsutter.com/2018/07/02/trip-report-summer-iso-c-s...

Asserting that no one wants their code to correctly handle errors is a bold claim.

> So go back about one year, and we could vote about it before it got into the standard, and some of us voted no. Now we have a much harder problem. This is part of the standard proposal.

Offtopic, but this is a problem in the web world, too. Once something is on a standards track, there are almost mechanisms to vote "no, this is bad, we don't need this". The only way is to "champion" a proposal and add fixes to it until people are somewhat reasonably happy and a consensus is reached. (see https://x.com/Rich_Harris/status/1841605646128460111)

> It feels like piling on ever more complexity to a language which has already surpassed its complexity budget, and given that the feature comes with its own set of footguns I'm not sure that it is justified.

This is a common sentiment about C++, but I find it very interesting that everyone seems to have a different feature in mind when they say it.

C++ isn't the first language to do things, but was/is often the first mainstream language to do things.

And then people complain about C++ for doing it wrong, or its complexity, and show language 'X' that does it better/right, but only because they saw C++ do it first, and 'not quite right'.

I expect contracts to be similar - other languages will watch, learn, and do version two, and then complain about c++, etc.

It took 'quite a while' to get rid of auto_ptr, for example.

If it wasn't for the fact this is a language feature, it would be better off in boost where it can be tested in the wild.

Is there any good documentation about contracts? https://en.cppreference.com/w/cpp/language/contracts.html is incredibly confusing - its first displayed example seems to be an edge case where the assertion itself causes a mutation?

https://en.cppreference.com/w/cpp/language/function.html#Fun... is vaguely better, but still quite dense.

IMO the syntax makes things hard for a newcomer to the syntax to understand, which I see as core to any programming language's goals of community.

    double square_root(double num) asserts_pre(num >= 0)
would have been far more self-evident than just

    double square_root(double num) pre(num >= 0)
But I suppose brevity won out.
Sadly, transparent hash strings for unordered_map are out.
I don't care until they stop pretending Unicode doesn't exist.
> Second, conforming compiler and standard library implementations are coming quickly. Throughout the development of C++26, at any given point both GCC and Clang had already implemented two-thirds of C++26 features. Today, GCC already has reflection and contracts merged in trunk, awaiting release.

How far is Clang on reflection and contracts?

As long as programmers still have to deal with header files, all of this is lipstick on a pig.
I don't understand this at all. There are modules.

But headers are perfectly fine to deal with and have been for decades and decades! Next you'll be arguing that contents pages in all books should be removed.

What an absurd attitude. The gymnastics to avoid circular inclusions alone are something nobody should be giving a thought to in the 2000s.

"But headers are perfectly fine to deal with and have been for decades and decades!"

I would have thought this was a joke... but your follow-up indicates otherwise.

So what are you going to float next? "So what if people broke their arms hand-cranking their cars to start them! People did it for years, so we shouldn't move to electric starters! Or automatic chokes!"

"And these electric ice boxes are for the birds! Speaking of which: People flying through the air in machines? POPPYCOCK!"

I use modules in all my private projects since the last two years.
I am actually excited for post and pre conditions. I think they are an underused feature in most languages.
Postconditions are in conflict with programmers' love of early returns.
The "erroneous behavior" redefinition for reads of uninitialized variables is really interesting: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p27...

It does have a runtime cost. There's an attribute to force undefined behavior on read again and avoid the cost:

    int x [[indeterminate]];
    std::cin >> x;
I envy the person that will walk into a c++ codebase and see "[[indeterminate]]" on some place. And then they will need to absolutely waste their time searching and reading what "[[indeterminate]]" means. Or over time they will just learn to ignore this crap and mentally filter it out when looking at code.

Just like when I was learning rust and trying to read some http code but it was impossible because each function had 5 generics and 2 traits.

On a quick read of the paper, I see two surprising things:

1. If there’s no initializer and various conditions are met, then “the bytes have erroneous values, where each value is determined by the implementation independently of the state of the program.

What does “independently” mean? Are we talking about all zeros? Is the implementation not permitted to use whatever arbitrary value was in memory? Why not?

2. What’s up with [[indeterminate]]? I would expect “indeterminate” to mean that the variable has a value that happens to be arbitrary (and may contain sensitive data, etc), not that it turns back into actual UB.

Contracts feel like the right direction but the wrong execution timeline. The Ada/SPARK model shows how powerful contracts become when they feed into static verification — but that took decades of iteration on a language with far cleaner semantics. Bolting that onto C++ where UB is load-bearing infrastructure is a different beast entirely. The real risk isn't complexity for complexity's sake — it's that a "minimum viable" contracts spec gets locked in, and then the things that would actually make it useful for proof assistants become impossible to retrofit because they'd break the v1 semantics. Bjarne's concern about "incomplete" is more worrying to me than "bloated."
std::execution is very interesting, but will be difficult to get started with, as cautioned by Sutter. This HPC Wire article demonstrates how to use standard C++ to benefit from asynchronously parallel computation on both CUDA and MPI:

https://www.hpcwire.com/2022/12/05/new-c-sender-library-enab...

Overlapping communication and computation has been a common technique for decades in high-performance computing to "hide latency", which leads to better scaling. Now standard C++ can be used to express parallel algorithms without tying to a specific scheduler.

NVidia is the main sponsor of this kind of work, and a few key figures are nowadays on their payroll.
I am curious what is their strategy to get language to the stage where the US government will make it cosher for new projects
"Japanese soldier who kept fighting 29 years after World War 2"
If you ask me (and why wouldn't you? :-)...) I really wish the C++ WG would do several things:

1. Standardize a `restrict` keyword and semantics for it (tricky for struct/class fields, but should be done).

2. Uniform Function Call Syntax! That is, make the syntax `obj.f(arg)` mean simply `f(obj, arg)` . That would make my life much easier, both as a user of classes and as their author. In my library authoring work particularly. And while we're at it, let us us a class' name as a namespace for static methods, so that Obj::f the static method is simply the method f in namespace Obj.

3. Get compiler makers to have an ABI break, so that we can do things like passing wrapped values in registers rather than going through memory. See: https://stackoverflow.com/q/58339165/1593077

4. Get rid of the current allocators in the standard library, which are type-specific (ridiculous) and return pointers rather than regions of memory. And speaking of memory regions (i.e. with address and size but no element type) - that should be standardized too.

The C++ WG is like any other open source project, even when it doesn't look like it.

Someone has to bring a written spec to WG21 meetings and push it through.

And like in every open source project that doesn't go the way we like, the work is only done by those that show up.

2 sounds good, but it will break a lot of existing code what suddenly does something different. At least so far every version of the rules someone has come up with has had a real world example of code that would be seriously broken if it was in place.
I think you cannot get an idea of in hiw many ways 2. can break...
re 3, clang has [[trivial_abi]] (and I believe GCC is also implementing it. But it won't be applied to standard types by default, because of course is ABI breaking. You'll have to derive your own.
I switched from C++ to Java/Python 20 years ago. I never really fit in, I just dont understand when people talk about the complicated frameworks to avoid multithreading/mutexes etc when basic C++ multi threading is much simpler than rxjava or async/await or whatever is flavor of the month.

But C++ projects are usually really boring. I want to go back but glad I left. Has anyone found a place where C++ style programming is in fashion but isn't quite C++? I hope that makes sense.

That place is C++/Lua, with most of the code in Lua. Concurrency model is thread-per-lua-state. Interthread comms is message passing implemented via textbook c++11 atomic and condition variables. Lua is just a small C library so the style remains very friendly to those who like C with classes.
It looks like they didn't even add _BitInt types yet. Adding concepts but not adding _BitInt types sounds insane considering how simple _BitInt types are as a programmer (not sure about implementation but it already works in clang).
If C++29 was exclusively about quality-of-life improvements, improving what exists, I'd bet the community wouldn't mind too much.
Hosting the meeting in Croydon and not letting people leave until the thing is signed-off is definitely a cunning strategy. Never want to work down there again, ever.
Quite unrelated to the main topic, but shouldn't it be Croydon, London? I have never heard anyone called it London Croydon before. Generally addresses/places go from most specific to least and given Croydon is an area of London it should go first.
C++ is so tantalizingly close to being an amazing embedded c++ language if they could JUST support first-class polymorphism.

Embedded is such a perfect fit for interface-based programming, but because it cant determine call resolution outside of a single source file, EVERYTHING gets vtable'd, which ruins downstream optimizations.

There's some ugly workarounds.... CRTP, c-style (common header + different source files. To the person who says "use templates!".... no. I dont like templates. They are verbose, complex, and every time i try to use them they I end up foot-gunning myself. Maybe its a skill issue, but if you designed something that most people cant figure out, I'd argue the design is wrong.

C++ is SOOO close to doing compile-time polymorphism. If just needs a way to determine type across source files, which LTO sorta-kinda-but-not-really does.

I've seen some examples of C++ contracts replacing CRTP, but it used templates, which again, not a fan of.