Hacker News new | past | comments | ask | show | jobs | submit login
C++20 Is Feature Complete; Here’s What Changes Are Coming (hackaday.com)
78 points by jandeboevrie 85 days ago | hide | past | web | favorite | 64 comments

This article might seem confusing.

That's because it is. There is hardly a paragraph in it that is wholly correct, where they actually mean anything.

C++ itself is much easier to understand than the article.

The real purpose for all the constexpr-related apparatus, as well as much of Concepts, is to make it much rarer that anybody needs to do "template metaprogramming". Instead of writing Template Metaprograms to run at compile time (a very strange functional pattern-matching language practically nothing like C++) you can usually write ordinary C++ code.

Coroutines are a new flow control primitive showing up in lots of languages lately. The C++ version is the same as the others.

The main benefit you will see from Concepts is overwhelmingly better error messages when you misuse a library component, whether Standard or your own.

Modules is a big step toward enabling a modern build infrastructure, as already seen in lots of newer languages that got benefit of hindsight.

All the old stuff is still there, because billions of lines of old code still use it. You don't have to use it in new code, but it all still works.

The biggest difference between old and new C++ code is that good new code uses value types more, and reference types less, making everything safer.

Coding modern C++ is overwhelmingly more fun than coding C++98 was, but it is just as fast as ever, and better than ever for writing fast, powerful, nice-to-use, no-compromise libraries.

I got had to fight with template metaprogramming lately, and I can't be happier than reading about this. Do you have any sources when one can learn in a non-confusing way about this new stuff, especially Concepts?

If you're looking for a high-level example, the Wikipedia article one where a function is constrained to only accept an argument which implements operators "==" and "!=".


I’m not a C++ dev. I took one class of it in college and even then it was 90% C and only hit pointers and classes on the final unit.

But holy smokes this is not your grandmother’s C++, is it just me or is the language trying to be all things to all people? It’s getting too big, no? I mean how long do you have to be writing C++ code to fully master the language? Or can you be a high level dev without ever touching the new features? I’m assuming production codebases are likely still stuck on older versions of the language and might never move on.

I hope golang doesn’t grow this large over time.

Yes, it's very complex and hard to stay on top of current best practices.

However, every one of the major features listed in this post replace an existing language feature with something that is easier/safer/less verbose. For new code you shouldn't have to use the old features, and you can just rely on the new ones. Existing code is trickier, which is already a problem for large C++ codebases. You'll find dramatically different styles depending on when the code was written.

All in all, though, the recent changes have made C++ much more pleasant to program in. They're mostly less complex for an application developer than the things they are replacing, and the really complex bits (concepts, etc.) are only needed for writing complicated template libraries.

"every one of the major features listed in this post replace an existing language feature"

That is the part that annoys the hell out of me in regards to C++. Nothing ever gets replaced, things just get added on top of everything. And to add to that there is generally very little indication which is the "new, safe and cool way" and which is "old, shoot yourself in the foot" way of doing things. Like std::string is cool and generally you want to use it everywhere... except you can use []char everywhere and be completely unaware that you are doing anything wrong (well, until you segfault on memory access). Or unique_ptr and shared_ptr and auto_ptr. Cool things, but you can use a regular pointer in their place and again, never realize something is wrong (again, until you segfault). And every C++ book I ever saw happily discusses raw pointers and memory allocation and []char strings without ever giving you any warning that under most normal circumstances you should not use any of this.

Yeah, I agree that part is frustrating - it's very difficult to stay on top of current best practices, especially when even experts (and many "experts") disagree on best practices.

The "Nothing ever gets replaced" problem is a direct consequence of the committee's focus on backwards compatibility. That compatibility has been absolutely crucial for the language's continued success. Backwards-incompatible changes would result in even more divergence between the C++ dialect supported by various compilers and compiler versions, and would probably result in an even worse version of the problems that occurred in the Python 2->3 transition.

In my experience, the the ABSL "Tip of the Week" posts[1] are a great source for "best practice" info, but they aren't exhaustive, and some are specific to the ABSL libraries, rather than general C++.

[1] https://abseil.io/tips/

"That compatibility has been absolutely crucial for the language's continued success"

I am not sure I buy that argument. The problems with Python 2->3 were mostly about Guido and his management style rather than actual language. People were not sure how long Python 2 would be maintained and whether or not they would need to support both and how that would work and all sorts of things like that. And Python 3 was not very complete on release, with a lot of things changing rapidly and backward compat getting shoehorned back into P2. With C++ committee approach this is a lot less likely to be a problem.

I think the reason things never get dropped is because C++ is not well designed. It is basically C with OOP and generics bolted onto it. So low level C stuff like direct memory access is built-in. And since OOP is kind of an afterthought, there is a split between parts of language that do fall under the OOP system and parts that don't. So you can introduce something like std::string using the OOP system and make it super safe, but you cannot replace C strings with it simply because C strings (and direct memory pointers in general) are a core part of the language that is not connected to OOP in any way. Same goes for smart pointers and iterators and functor structs and what not. Most of the cool things in C++11 and C++17 are firmly planted in the OOP world and cannot affect anything that is the "original C" part.

The act of not replacing things though doesn’t go further enough imo — if b is truly better in every way and also functionally equivalent to a then in the version that b came out in it should only have b and deprecate with compiler warnings or fail to compile with a so as to move the language forward

That's an option, but it's a risky one, because you could end up with a balkanized language with many different C++ dialects depending on compiler version and platform. The amount of existing code in the world is huge, and not every organization has the resources, knowledge, or desire to move to the new hotness every time an improvement to the language was made.

The Python 2->3 transition is an example of what can happen when you make backwards-incompatible changes to existing language features. We're more than a decade in, and there are still huge volumes of code at major organizations that haven't made the switch. This happened despite the fact that the people proposing the change also controlled the change and release process for the major implementation of Python, a case which is not true for C++.

It's also difficult because many proposed backwards-incompatible changes or deprecations would break ABI compatibility, which would prevent a library and binary (or 2 libraries) that were compiled using different compiler versions from inter-operating. This breaks a core workflow for many C++ users.

To get a better understanding of the committee's priorities, I would recommend looking at "The C++ Programmer's Bill of Rights": https://isocpp.org/blog/2017/07/what-should-the-iso-cpp-stan...

It's not a formal commitment from the committee, but it will give you a sense of what their priorities are.

> Nothing ever gets replaced, things just get added on top of everything.

I mean, look at all the angst around Python 2 -> Python 3. People don't want features to be replaced.

What angst? Python 3 is a better language than python 2. Python 2 is still supported, but everyone is encouraged to write python 3 from now on. I have been a python dev for years and I think the only change in python 3 that actually annoyed me rather than make me happy was support for function argument unpacking.

That transition was the worst. I write a lot of python and golang of late and am convinced that opinionated (only one way to do things) languages are the way to go as they tend to be simpler.

I haven't touched C++ in ages, but wouldn't there be standardized linters that can ensure the use of newer safer constructs?

Absolutely! clang-tidy has a suite of modernisation tests and in many cases can apply fixes automatically.

> every one of the major features listed in this post replace an existing language feature with something that is easier/safer/less verbose

I'd argue that the each new feature adds on top of an existing one. 30+ years of existing knowledge won't vanish, and will cause decades of unintended Frankenstein codebases (followed by decades of even more Frankenstein ones).

Does anyone know of a mind-map or info-graphic that sort of lays out the new features and which older features they replace. Something to help someone who hasn't looked at C++ in years get a feel for how to map things?

That makes sense. So you could take a C++11 codebase and incrementally change things to C++20 (using a complaint compiler of course). I wonder if there will be a huge market for people who truly understand all versions of the language who will be consultants hired to upgrade large codebases

Backwards-compatibility means you shouldn't actually have to upgrade large codebases. If the codebase isn't changing much, then you can leave it as is, and it will continue to work with new compilers. If you are making changes, then you can add C++11/C++20isms to the parts of the codebase that you're working on, and leave the rest alone. No need to bring in a consultant to change the whole thing.

> is it just me or is the language trying to be all things to all people?

Well yes, in the sense that it's a systems programming language designed not to be a single-paradigm language (you can write procedural, or somewhat functional, or classic OOP, or generic functions-based OOP) and to be very efficient at all.

Some of the features are seemingly arcane in order to preserve the zero-cost abstraction approach as much as possible.

> Or can you be a high level dev without ever touching the new features?

So some features are arcane as I wrote above but some are deliberately high level, designed to make it easier to write safe, efficient high-level code without getting into the weeds. Being able to type

    for (auto& a_frob : from_manager) ...
and have it be fast, efficient and not leak memory is a feature, right?

> I hope golang doesn’t grow this large over time.

Go's explicit design goals are the opposite: have only a few constructs, a specific "opinion" as to how things should be done, and to deliberately limit expressiveness in favor of other objectives. So I doubt it will come close.

Edit: I don't agree with go's design criteria, but I respect them.

One of the worst interview questions I have had was "Rate your C++ knowledge from 1 - 10".

I had just finished my second year of college, and although I felt fairly confident in my C++ abilities I had no idea how to answer. I thought it would be best to be honest and said "4" based on the subset of the huge language I knew (honestly this rating was probably too high at the time!).

One of the interviewers was obviously unhappy with the answer, and was unpleasant the rest of the interview. I have always wondered what they expected from such an vague question.

>One of the worst interview questions I have had was "Rate your C++ knowledge from 1 - 10".

>One of the interviewers was obviously unhappy with the answer, and was unpleasant the rest of the interview. I have always wondered what they expected from such an vague question.

I knew enough of C++ to know my knowledge on the subject is approximately close to Zero.

Basically no one on earth knows C++, they mostly know a subset of it.

*C++ here referring to Modern C++, Pre 2000 era C++ was still manageable.

Edit: On that thought it seems to me every PL in 90s were all manageable. Somewhere along the line things got ugly.

I love asking this question! I almost always get “7” as an answer! Except one notable time: the interviewee said, at first, “seven”... then he stops, slowly makes eye-contact and says “no: 10.” Brilliant! Who does that!?

I’ve interviewed hundreds of candidates; HR has relayed to me that many candidates requested that HR tell me that they loved being interviewed by me, even though the interview was very, very hard; they say they were surprised to learn things, and also happy I was so interested in them as s person.

This always made me happy; I had to sacrifice a teaching career to program.

Curious as to why you love asking this question? I wonder what data you are trying to glean from this question. It's a very subjective question and wouldn't surprise me at all if the number of years experience a candidate has in that language is inversely proportional to the answer you're given.

I often get this question from recruiters hiring front end developers: From 1 to 10, how well do you know Javascript? I've given 8 for as long as I remember but often I think to myself if the people who wrote the V8 engine are 10 by default, there is no way in hell I'm even close to an 8.

A good self-rating strategy in an interview would be to try and percentile yourself among the people based on your knowledge and try to justify it with humility. C++ is huge, I expect I know more than 80% of the people due to (years of experience, different kinds of projects, yada yada), but I feel i have only been able to explore like 50% of the language so far (concretely learn that is) and there’s more to learn like (1, 2, 3..) and probably more that I might have missed completely.

It’s almost always 7. The actual question I ask is “rate yourself on a scale from one to Bjarne”. Bjarne Stroustrup was the principle in the group I did my PhD, and he rates himself a 7, so when interviewees give ‘7’ as the answer, it makes me laugh.

Maybe they perceive it as a calibration question: "do you know how much you don't know" and "how much are you going to overpromise if you start here"

The way I ask the question is done to relax the candidate and make them start to think about the only person who matters in the room: themselves. I’m looking for intellectually curious people; a bit of modesty & self-reflection tend to go along with that.

Technical skill is a bit irrelevant, as essentially no one does the sort of low level SW our team does, anymore.

Do you ask it with or without a reference for what scale you're talking about?

I got a bunch of those once in an interview, but it was fine because they gave good guidelines for what they meant with the numbers and asked about a bit more specific areas.

Do you breed flying pigs too?

It’s just a trap to quiz people on language errata when they say a high number the guy would have been just as unpleasant in a different way.

The safe answer to this horrible question is 7. If they are expecting you to be an expert as an undergraduate, your mentoring possibilities are probably nil. They also probably associate unfamiliarity with inability. You probably wouldn't want to work there.

I agree this is a bad question, but when people ask, they almost always mean relative to your peers. they're not trying to decide whether to hire a summer intern or a senior dev. they just wanted to hear that you were better than most of your classmates.

I guarantee you his/er knowledge was probably a 3 or lower. If this were reddit I would ironically reply they clearly were just jealous of you or didn't believe you had such a well-developed grasp of C++ fresh out of college.

If this was reddit, I would reply how it is funny that you imply that you would not say that on hacker news, but you actually did indirectly

Oh yeah, C++ has been huge for decades. You pick a subset and program in that. The changes in C++11 had structural implications that took years to work through which is why it was late. The working name was C++0x because they expected to release it in '08 or maybe '09. http://www.stroustrup.com/C++11FAQ.html

> Oh yeah, C++ has been huge for decades. You pick a subset and program in that.

My impression is that the C++ standards committee sees the standard like a pile of papers on a professor's desk, where most programmers only need to understand what's currently visible on the top. And so they keep on adding papers to the top, they're getting the least-bad combo of innovation and backwards-compatibility.

My experience has been different. These days I mostly deal with codebases that are about 50% original C++ code, and 50% third-party code pulled in via CMake "super builds".

Even within the first 50% that's ostensibly under the control of a single organization, I find a large variety of C++ coding styles in effect. Continuing with the papers-on-desk metaphor, I generally have to deal with code that draws from the entire stack of papers.

This is what people say, how will C++ then not turn out like lisp then? Lisp became so idiomatic that people couldn't share code.

> Lisp became so idiomatic that people couldn't share code.

That is only a false meme spread by non-Lisp programmers.

Numerous other reasons explain Lisp's failure to take flight. Nobody agrees on which exactly they are, only that there are plenty of them.

I feel like this is a sort of meta joke.

> I mean how long do you have to be writing C++ code to fully master the language?

To be honest I don’t think you can ever fully master the language.

You could, at one point. C++98 and C++03 were minor updates, meaning C++ had 22 years where learning it wasn't a fast moving target (between C++89 and C++11). I would happily call myself an expert in that dialect of C++, but getting there took 5-10 years.

I can't call myself a C++ expert anymore, and, in fact, find it hard for anyone to, because with a language so complex, idioms and best practices aren't evolving at the same rate that the standard is changing, especially in cases where one has to deal with a mix of modern C++ and legacy (C++03 and earlier) C++.

I recently started trying to learn c++ and I'd say I've got the basics down.

Sometimes I'll watch a talk by Scott Meyers or Jason Turner and realize how little I know, and how deeply complicated things can get. Then I go back to my code base and continue being productive writing useful code. I know it's probably not perfect, but it's still satisfying.

As for reaching perfection or mastery, that's an enjoyable journey, even knowing that the final destination is likely unreachable.

I don't write cpp but it seemed c++11 and later were almost shrinking.

I am C++ developer by career and I am pretty much bashing the language all the time. To preserve my sanity I like to use C in after-hours. However looking up C++20 and the direction whole language is going I see there are things I would really like to see in C, while preserving C simplicity. Standardized attributes like [[fallthrough]] and others for functions seem nice. Anonymous functions are nice. They look a bit ugly, but function pointers already look even worse. It would not hurt to have modules and consteval functions in C, but then one still needs templates to really ditch the preprocessor and that's a tough one to solve.

Having said all that C++ is really in a need of a clean cut between legacy features and the blessed way. Backwards compatibility is a noble cause, but there is also the whole weight it pulls around. Maybe something like [[deprecated]] attribute could be extended to handle more cases. Maybe C++ needs it's own "unsafe" block, something like

  [[unsafe]] {
    *((void*)0) = 0xDEAD;
Essentially having an ability to clearly mark all those different styles of different versions of C++ really. So that compiler could help you to control it and in case of a green field project totally guide you to use only the most modern idioms with an escape hatch. Of course the problem is that to help with the complexity more complexity would have to be added.

I am a bit on the crossroads. From one side I start to see, that there is some hope for C++. But on the other I feel like running away, especially since I'm looking for a job. In no particular order: C, Rust, Java, Kotlin, Scheme, Julia, Go, OCaml, Free Pascal, Swift, TypeScript, Lua/Terra, Zig.

I had a funny thing with C++. One project I worked on was used in the debug version all the time, to be able to drop to debugger when needed. At that point I started to wonder why not just use Java already, instead of trying to do a manual Java and fail at it.

Despite the slight differences they have from the C99 version of them, I'm pretty happy to see designated initializers in C++20

Sounds amazing. Anyone have code examples that integrate a lot of the newer stuff?

Dumb question. Why isn't omitting 'return' always an error in gcc rather than just a warning?

In any case, just add -Werror=return-type to your compiler flags... After I had forgotten a return once, that option saved me several times.

int foo() { bar(); } is a perfectly well-formed function as long as bar() never returns. Allowing this without requiring bar() to be annotated as noreturn is generally considered a mistake, but correcting it would break existing valid programs.

> but correcting it would break existing valid programs

That's very often the case when enhancing static safety guarantees. And that's often worth it.

C++17 already made backward compatibility a non-goal (within reason, obviously) and broke previously valid programs.

I don’t care that my previous comment post has been downvoted, but I do want to clarify that I wasn’t being facetious; C++17 removes a number of old features and constructs that had been previously deprecated and there exist programs that compiled under C++14 that need non-trivial changes to compile under C++17.

Likely answer is, doesn't really cause problems for anyone in practice. Experienced C++ programmers fix warnings.

Also the ABI specifies how to call and get the return value of a function. The long and the short if it is the execution thread doesn't go off the rails if there is a mismatch in expected behavior. Your data may be garbage tho.

It would be nice if the program would abort if a non-void function returns without a value. The only cost would be a slightly larger executable.

Looks pretty good. But I don’t understand why they don’t do string interpolation like C# and others do.

“I= {I}”

Is much better and less error prone than

“I= {}”, I

Or am I missing something?

Probably some syntactical reason. If you allow arbitrary expressions inside string interpolation, you'd need to have some form of state in your lexer to figure out when to lex the characters into tokens or just keep them as raw characters. It's not so easy as looking for another brace, as you can have expressions that have braces (lambdas). Plus, string interpolation can then be nested, which you may not want.

The format library is a pre-existing library which is being standardized. String interpolation cannot be implemented in a library, and requires language extensions. Perhaps they should have done that instead, but that's a significantly more complicated task than merely adopting something that's already well tested and proven (and even that was far from trivial).

I am not necessarily opposing string interpolation as a language feature, but I have an idea how could it work as a library. Implement string suffix and overload comma operator or overload reminder operator. It would look like this:

  "Hello {} {}!"i, 2, "worlds"
Or with reminder operator as in Python:

  "Hello {} {}!"istr % istr(2, "worlds")
But yeah, enough of this.

C++ (and C) have a fairly odd characteristic in that it is really hard to definitively figure out what is an identifier.

It's one of the reasons C++ takes so long to compile.

It's why the "modern" languages all seem to be converging on having an explicit token that signals "This thing is an identifier : this thing is a declaration".

I don't think you'd be able to evaluate your expression without some kind of runtime reflection. Specifically, how is a standard library method supposed to interpolate {l}? It doesn't have any information about which variables are present in some kind of format string.

I am pretty sure C# does the interpolation at compile time but it probably helps that it has a string type as first class citizen to the compiler has more information.

I've had C++98 at school, but how would I learn C++17? Scott Meyers wrote C++14 but he retired from C++ development so what are the best alternatives?

Changes from c++14 to c++17 are nowhere near as dramatic as c++98 to c++11, so you can go with Scott Meyers and fill in the gaps from cppreference.com, for example.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact