
C++ 20: The Core Language - juice_bus
https://www.modernescpp.com/index.php/c-20-the-core-language
======
gumby
I'm glad this hasn't turned into (so far) the usual "c++ is dumb" flame fest.

I've really enjoyed programming in c++17 for the last three years (I had the
luxury of starting from an empty buffer) and find the language pretty
expressive. If you are able to use it as a "new" language, ignoring its C
roots and features that exist pretty much just for back compatibility, it's
really quite expressive, powerful, and orthogonal.

I'm actually pretty glad the c++ committee has been willing to acknowledge and
deprecate mistakes (e.g. auto_ptr), to squeeze out special cases (e.g. comma
in subscripting) and to attempt to maintain generality. Conservatism on things
like the graphics standard is reducing the chance of the auto_ptr or std::map
mistakes.

~~~
beetwenty
The thing that has really kept me from getting behind updates to the C++
universe is the lack of progress on improving the state of build tooling. It
is miserably underengineered for modern, dependency-heavy environments. C++20
does introduce modules, which is a good push towards correcting the problem,
but I'm still going to be "wait and see" on whether the actual implementation
pans out.

~~~
gumby
Well, there's Conan, which helps a bit, but these days what I simply do is use
CMake to download a package from GitHub or wherever and build it.

Sadly the C++ ABIs are standardized the way that C ABIs are (I'm OK with _why_
but it's unfortunate in that it creates a barrier) so you have to have
separate libraries compiled with g++ and clang++ if you use both on your
platform (we use both because they catch different bugs, and for that matter
exhibit different bugs). But it means you can't simply install, say, fmt in
any system-wide directory like /usr/lib or /usr/local/lib

Just as an amusing side note: Common Lisp used to be criticized for the
massive size of its libraries and later likewise C++. It was true they were
quite large. Now both are criticized for their tiny libraries. Which by
today's standards they are.

~~~
bsder
> Just as an amusing side note: Common Lisp used to be criticized for the
> massive size of its libraries and later likewise C++.

Part of "size of libraries" is "mental size of libraries".

And C++ and Lisp and have very large mental spaces for their main core
libraries. A "String", for example, carries a huge amount of mental baggage in
those languages. In most other languages, a string is extremely
straightforward because it was designed into the language from the start.

~~~
missblit
It's possible I'm just used to it, but I've never found std::string more
complicated than, say, python (what's up with unicode in 2 vs 3?) or
JavaScript (UTF-16 = surrogate pair pain).

It's essentially a std::vector<char> with a few random convenience features
bolted on.

I guess some of the confusing points are: not unicode aware, string literals
aren't std::strings by default, c_str returns a pointer to a buffer with
length one greater than the string length, and the usual C++ quirks like why
is there both data and c_str?

~~~
saagarjha
> the usual C++ quirks like why is there both data and c_str

The usual C++ response: for backwards compatibility, because data was not
required to null-terminate prior to C++11.

------
DoofusOfDeath
In commercial settings, I encounter several barriers to using C++ versions
newer than 2011:

(1) Most C++ code _I_ encounter is C++11, and I deal with lots of projects.
It's rarely sensible to change the language version of a large code base
without a very good reason.

(2) Many developers are well-familiar with C++11.

(3) There's no _widespread_ perception that C++14 or later bring compelling
language improvements.

(4) Some (most?) C++11 developers are already uneasy with the complexity of
C++11, and aren't eager to incur the learning curve and (perhaps) new set of
pitfalls associated with newer C++ versions.

(5) Some C++11 developers look at the language trajectory, especially in terms
of complexity, and have decided that their next language(s) will be e.g. Rust
or Julia instead of C++14, C++17, etc.

I suspect these factors all contribute to the momentum that C++11 seems to
have.

~~~
jandrewrogers
I don't encounter these barriers in commercial settings. The biggest barrier
is compiler support if you target environments with different compiler
toolchains. Each new version of C++ brings features and bug fixes that make
code simpler. It actually _reduces_ complexity from the perspective of the
developer. The forcing function for upgrading C++ versions in my teams is
always that it would greatly simplify some immediate problem or allow us to
remove a gross (but necessary) hack due to the limitations of prior versions.
At least with the LLVM toolchain, upgrades have been nearly issue-free so
there is little to recommend not doing it. C++17 is a big upgrade over C++11
functionally. Developers that do not see compelling improvements probably
weren't using most of the functionality of C++11 anyway.

While the number of features and quirks in standard C++ grows with each
version, the subset that a developer needs to remember to write correct
idiomatic code is _shrinking_ with each new version as capabilities become
more general and the expression of those capabilities simpler. There is a new,
simpler, and vastly more capable language evolving out of the old one and you
can increasingly live almost entirely within this new language as a developer.
I hated classic C++ but I actually really like this new C++, and it allows me
to write far less code for the same or better result.

There are still many things that C++ can express simply and efficiently that
Rust, Julia, etc cannot. If you work on software that can take advantage of
that expressiveness (e.g. databases in my case), the cost of changing
languages is quite large.

~~~
brylie
How does a developer who is new to C++ learn just the modern idiomatic style?
Is there a "C++, the good parts"?

~~~
lenkite
C++ Crash Course:
[https://lospi.net/c/c++/programming/developing/software/2019...](https://lospi.net/c/c++/programming/developing/software/2019/07/28/cpp-
crash-course.html)

C++ 17: [https://leanpub.com/cpp17](https://leanpub.com/cpp17)
[https://leanpub.com/cpp17indetail](https://leanpub.com/cpp17indetail)

------
lasagnaphil
Right now my biggest things I like from C++20 are:

\- Concepts (Now I can use static polymorphism without all those SFINAE
template hacks)

\- Designated Initializers (Finally!!! Using POD structs became way more
convenient now)

\- Coroutines (Would be pretty nice for writing games / interactive
applications)

The things I don't have any interest in (but don't care if it's in or not)

\- Ranges (Too much complexity for something you could do with plain old
for/if loops...)

The things I'm worried about:

\- Modules (Theoretically really good, but in practice the whole thing is
starting to become a mess, especially when it's interacting with the
preprocessor and external libraries, and when trying to preserve backward
compatibility.)

~~~
jokoon
I have hope for modules because they can improve build times. Not exactly sure
they would improve build time but if it's true, it would be a massive
improvement.

~~~
saurik
Meanwhile, I am deeply concerned about modules, as it seems like the kind of
feature that is going to massively harm build times by making it much more
difficult to do truly independent distributed builds (which right now is
pretty easy with C/C++ due to its separate compilation and extremely explicit
inter-file dependencies).

~~~
naasking
Modules make separate compilation possible. C++ does not really have separate
compilation right now.

~~~
saurik
I do not understand this comment, as I have done separate compilation every
day with C++ for over two two decades: the model inherently _only_ allows
this, as every translation unit absolutely must be compiled separately and
then linked... you don't even have a choice in the matter. I have also used
both off-the-shelf and custom distributed build systems (most recently, I have
deployed one which does insanely-parallel builds of a C++2a codebase using AWS
Lambda), which pair extremely well with the explicit file-oriented
dependencies that can be reported by each translation unit and used to
determine which parts of the build are now stale given changes to the
filesystem. I have never seen languages with module systems support even basic
separate compilation, and it terrifies me; meanwhile, the flags I have seen
being added to clang for attempting to preserve separate compilation behavior
with the modules spec doesn't leave me feeling good about the endeavor. It
could be my fears are unjustified, but it is extremely strange and somewhat
annoying that the advocates for it don't ever seem to appreciate the state of
the art for the status quo.

~~~
naasking
> I do not understand this comment, as I have done separate compilation every
> day with C++ for over two two decades: the model inherently only allows
> this, as every translation unit absolutely must be compiled separately and
> then linked... you don't even have a choice in the matter.

Except if your headers include macros or templates, which must be evaluated
every time. This is not separate compilation. What C/C++ developers have been
doing for 20 years is jumping through hoops to incrementally reuse previously
compiled results because C/C++ violate basic modularity principles [1]. They
call it "separate compilation", but it's a pale shadow of true separate
compilation.

Proper modules would enforce abstraction boundaries so true separate
compilation becomes possible. I can't speak to the specific C++ proposal here,
but enabling separate compilation is exactly what modules are _for_.

[1] [http://llvm.org/devmtg/2012-11/Gregor-
Modules.pdf](http://llvm.org/devmtg/2012-11/Gregor-Modules.pdf)

~~~
gpderetta
Normally use of templates do break separate compilation but it can be
recovered, and it is routinely done on large codebases, via explicit template
instantiation. The ergonomics are not great of course and hopefully modules
will improve things.

------
rosshemsley
Features I wish C++20 had:

* An opinionated, modern packaging and dependency story (like go modules, Rust crates)

* built-in library support for logging, http, zip, gzip, json, yaml, template rendering, RFC3339 datetime reading/writing

* the dream: compliant compilers must be able to compile down to static binaries, cross compiling built-in.

Features C++20 actually has:

* new fancy spaceship operator that I'll now have to learn and never use...

~~~
zelly
> built-in library support for logging, http, zip, gzip, json, yaml, template
> rendering, RFC3339 datetime reading/writing

There is a Boost library for each of those things.

> An opinionated, modern packaging and dependency story (like go modules, Rust
> crates)

> the dream: compliant compilers must be able to compile down to static
> binaries, cross compiling built-in.

You can use Conan or vcpkg. LLVM basically solves the cross-compiling issue
since you can take the IR to any platform that has a LLVM target.

Neither of these are feasible to include in the International Standard because
C++ runs on more than amd64 and would make a lot of obscure platforms no
longer compliant with the standard. Rust crates are nice, but people building
medical devices with C++ shouldn't need to worry about supporting an npm-like
monstrosity in their builds.

~~~
steveklabnik
LLVM IR is not platform independent.

Rust compiles on far more platforms than amd64, and Cargo works just fine.

Nothing forces you to depend on any packages you don’t want to.

~~~
zelly
> Nothing forces you to depend on any packages you don’t want to.

Nothing stops you, either, which is a problem for everyone in the future who
uses your code. The first reaction to any problem in JavaScript/webdev is to
google for a library to import to solve the problem. This is acceptable
behavior because the existence of a web browser implies powerful enough
resources to accommodate bloat. But this mentality isn't acceptable on other
systems and has even infected some basic functionality:

[https://crates.io/crates/rand](https://crates.io/crates/rand)

The random number generator for Rust has 6 dependencies. In C++, it's only
lib[std]c++. In Java, it's java.base.

~~~
pornel
Random number generation has trade-offs for speed, security, and thread
safety.

Most other langues with a "simple" built-in are unfit in some of these
aspects, so you may end up with a footgun and still have to find a
replacement.

In Rust you can choose which algorithms are used and how. And because it's a
regular package, it can be improved without breaking the language.

Note that number of dependencies doesn't mean anything. Some crates are split
into tiny deps for each feature, so that you can reduce binary size and
compile time if you disable optional features.

~~~
zelly
That's true for libc's naive rand() which is used by Python, JS, Ruby, PHP,
etc.

But stock C++ has many options for the random number generation algorithm:

[https://en.cppreference.com/w/cpp/header/random](https://en.cppreference.com/w/cpp/header/random)

As does Java and .NET. Without any dependencies and guaranteed to be portable.

> Note that number of dependencies doesn't mean anything. Some crates are
> split into tiny deps for each feature, so that you can reduce binary size
> and compile time if you disable optional features.

In theory I agree. It just seems like one of the persistent unsolved problems
in software is dependency hell (spawning the whole containerization movement),
so I'd like to avoid it if I could.

------
gumby
On thing I appreciate is mdspan -- multidimensional projections onto a regular
linear vector. I've always had to spin these myself which means they don't
fully participate as ordinary containers (who's going to go tho all that work
for their own application code).

I'm hoping I can map them into GPU space -- looks like the standard has
adequate control for this.

~~~
alexhutcheson
Does Eigen not work for your use cases?

~~~
gumby
That's a good call for a great library.

It's often overkill for what I do, especially as it can't use the same
compiler options as my tree normally does (they have to bend over backwards
for back compatibility; I don't). I do use it some places. I certainly don't
envy the hard work of library developers!

When I simply need a 2D or 3D resizable array it's often easier, as I
mentioned, to simply spin one up. Having that support "native" will be great.

------
afranchuk
I've been anxiously awaiting modules and concepts. Both are incredibly
important to reduce developer burden and improve the development experience.

Modules: While it is important to be able to fine-tune linking and compilation
in some settings, in most, and especially for beginners, this should be
handled by the compiler. Especially when compared to other modern languages,
C++ is much more complex to understand the toolchain and what's going on under
the covers with the dichotomy of compilation and linking. Header files were a
hack that have been around for too long, and there needs to be less separation
between the interface and actual binary code when compiling. This is a
headache both for novices and the experienced.

Concepts: The missing link for templates. Besides removing some of the
roundabout-ism of SFINAE by providing compile-time verifiable interfaces, I
think the biggest benefit of concepts will be the error messages. Right now,
the state of errors in heavily templated code is abysmal, and this translates
to a lot of wasted time for developers. Concepts should allow the errors to
indicate exactly what's wrong.

I can't wait to be able to use these in public code. Some compilers support
concepts with a flag already (and GCC 10 has it without the special flag),
though none support modules yet...

------
dgellow
Could someone describes the keyword "unlikely" and "likely" in a bit more
details? It seem to be a very niche thing to add to the language. Is it
expected that those hints will have an impact important enough regarding what
the optimizer can do?

~~~
bluGill
In some niches it is important.

Say you are writing a high speed trading program. At some point you get to the
"if(wouldMakeMoneyOnTrade())...". However for every time this passes and you
trade there are 1000 where it fails and you don't. However time is critical
because your competitors are using similar algorithms and so you need to beat
them - thus you put in a likely and ensure that the CPU jumps to the trade
code the fastest possible. Your competitors that use Java pay a CPU branch
prediction penalty here because the hotspot optimizer has noticed that the if
almost always fails and optimized for the false case. Thus you can make money
by beating your competitor to the trade. (Note, this doesn't mean you can't
use Java for your code, but if you do you need to manage that risk somehow)

~~~
saagarjha
A stop-the-world GC for HFT doesn't sound like it would work all the well…

~~~
pnako
Many HFT firms use C# or Java. Quite a few matching engines are written in
those languages as well.

The trick is to remember that garbage collection is not some sort of werewolf
that wakes up and decides to mess with your stuff whenever it feels like it;
it (can) happen only at certain, documented points. So you have to write your
code in such a way that it does not do memory allocations in the critical path
(which you would not be doing in C++ anyway, for a similar reason; malloc/free
is expensive).

Generally if you're doing HFT your critical path is not going to being doing
much anyway. A few reads, comparisons, maybe some trivial arithmetic and that
should be it.

~~~
gpderetta
For what is worth, at least in London, all the HFT firms I have worked with or
interviewed for use C++. As I'm a C++ programmer there is bias of course, so
my sample is probably not representative. Still I suspect that those that use
anything other than C++ are a small minority.

------
beezle
Been away from C++ a long time. If picking it up again, is it better to just
start with C++17 or 20 or stick to C++11 which seems to be the defacto
production version?

~~~
gumby
Depends on your needs. If you don't have a lot of or any legacy code yes, go
straight to c++17 (or even 20 though you won't be able to use many of the
features right out of a the gate, or without third-party libraries). If you
can do this you'll be glad you did.

I was able to start a project in c++17 in 2016, though at the time I had to
use boost::variant with the Xcode compiler and boost::filesystem for all three
compilers (only a limited use so I could even have skipped it). Also for some
complex third party libraries I had to make a little trampoline file that
compiled in C++14, or with special flags, and then call those entry points.

Since I was starting from a blank slate I also compiled everything with pretty
much maximal warnings an -Werror which really improved the code a lot,
something you can never get away with with legacy code (not to insult working
legacy codebases!)

------
Ididntdothis
I haven’t done C++ a while but I really like where this is going. It’s a
complex language for sure but I always liked about it that whatever needed to
be done the language would not get in the way. There is something to be said
for working in the language your OS and a lot of other libraries are written
with. You know that you have high probability of achieving what you need to
do. It may need a lot of work though.

------
gumby
With consteval (and its cousins), std::source_location and modules you could
pretty much compile C++ without the preprocessor. Hooray!

~~~
DerekL
There's still the need for logging and assertion functions, where you want to
test the debugging level or some other value before you evaluate the arguments
to the function. Right now, you need to use a macro, but there's a proposal:

James Dennett and Geoff Romer. P0927R2: Towards A (Lazy) Forwarding Mechanism
for C++. ISO/IEC C++ Standards Committee Paper. 2018. url:
[https://wg21.link/p0927r2](https://wg21.link/p0927r2).

------
CoolGuySteve
Hopefully between consteval and string literal template parameters, we'll be
able to detect literal const char* in templates.

Would be nice for my threaded logger to know if it can copy the pointer
instead of the whole string, knowing it was initialized statically.

~~~
MaxBarraclough
Wouldn't the ideal solution involve the const system?

------
eyegor
Is there a good "tutorial for modern c++" resource out there? The last c++ I
used heavily was c03 and a sprinkle of c11. I find reading modern c++ to be
somewhere between frustrating and an exercise in hieroglyphics thanks to how
much it's changed. Something along the lines of "basics of why to use the
different std pointers/views instead of raw pointers", lambdas, all the new
const-like bits, and whatever else have become "core" features.

~~~
karmicthreat
I've read "A Tour of C++" by Stroustrup. It was helpful in trying to catch up
to modern idioms for C++.

------
DeepYogurt
I'm not sure I grok the `<=>` operator and the example they show seems to just
show that `a == b`. Can someone explain what's going on with that?

~~~
inetknght
> _I 'm not sure I grok the `<=>` operator_

Think of `strcmp` which returns an int. The int can be <0, ==0, or >0\. That
same `strcmp` can then be used to implement all other standard comparison
functions. `operator <=>` is the generalized version of that.

~~~
johannes1234321
An important part there is: Most users will never call <=> themselves. However
somebody implementing a type can implement a single function and the compiler
will translate usage of <, <=, ==, !=< >=, > to the single function. Reduces
boiler plate in the implementation. (Think about it - most implementations of
> or < will often use the same logic already, spelling this out is "annoying";
mind that for performance reasons it can still be worthwhile to implement a ==
explicitly as equal comparison is often faster than ordering, but that's
something the type designer can chose)

~~~
cogman10
Do you have an example of when == would be faster than a comparison?

I can't think of any case that would have any appreciable difference in speed.

Is it mostly around eliminating branching logic?

Wouldn't there be a good chance that might be inlined and optimized away
anyways?

~~~
johannes1234321
On case is string comparison. When implementing == I can shortcut if length
doesn't matter the string can't be equal. When implementing <=> I however have
to iterate in any case. (While there the question then is if the shortcut is
really efficient, as the iteration might already stop on first character ...)

------
shaklee3
This book is worth checking out if you don't know c++17:

[https://www.bfilipek.com/2018/08/cpp17indetail.html?m=1](https://www.bfilipek.com/2018/08/cpp17indetail.html?m=1)

That guy has a great blog where he writes at length about each feature, and
the book is a compilation of that.

------
gridlockd
Why 'basic_fixed_string'? Is it really _so basic_ that it has to be mentioned
in the name? Is it just in case there might be a 'fixed_string' that isn't
quite as basic, in the future?

~~~
jcelerier
for the same reason that std::string is std::basic_string<char>

~~~
harry8
Ok. And what _reason_ is that?

~~~
jcelerier
what would you do instead ? surely you would not have std::string be a
template directly and type std::string<char> / std::string<wchar_t> instead of
std::string / std::wstring every time you want a string ?

~~~
gridlockd
...but unlike std::basic_string<T>, there is not template parameter for
std::basic_fixed_string and there is no typedef of it as std::fixed_string.

I suppose it opens up the possibility of adding std::basic_fixed_string<T>
later and then have std::basic_fixed_string just be a specialization?

~~~
gpderetta
cppreference doesn't have it yet, but as far as I can tell from P0259R0,
basic_fixed_string is a template, both parameterized on the char type and the
size N, and I can't see how it could be otherwise.

And no, if it weren't a template, it would not be possible to make it a
template in the future as it would be a breaking change.

------
sharpneli
Some parts of C++20 are really good, like most of what is stated in the
article.

But C++ would not be C++ if it had no shenanigans coming. Unless they have
changed things within some months the new calendar/datetime library is
hilarious.

It has features like being able to write a date like: 1/2/2000y. ooh fancy
operatoe overloading. Which one is month? The first one ofcourse as it they
didn’t standardize on any of the existing ISO standards, or allow you to
choose, but selected ”Customary US way” as the Only True C++ Way(tm).

Also do not forget the abuse of operator overloading like in the good 90’s
when misusing it was the recommended thing.

~~~
alexhutcheson
FWIW the absl CivilTime library is excellent:
[https://abseil.io/blog/20181010-civil-
time](https://abseil.io/blog/20181010-civil-time)

------
EamonnMR
Are there any quality tutorials for learning C++17 for basic tasks? Much "how
do I do X in C++" is very outdated from that perspective.

~~~
lone_haxx0r
I haven't read it yet, but No Starch published "C++ crash course" a month ago,
which teaches C++17 and looks appropriate for what you ask.

[https://nostarch.com/cppcrashcourse](https://nostarch.com/cppcrashcourse)

------
glouwbug
Did modules make it?

~~~
steveklabnik
Yes, they did.

------
xvilka
C++ should adopt Rust-like approach on deprecating things faster and a tools
like `cargo fix`/`cargo clippy --autofix` to automatically fix/suggest more
modern alternative to the deprecated language constructions.

~~~
AllanHoustonSt
There’s an initiative for Rust-like editions, but I think it’s a controversial
topic within the C++ committee.

------
lacampbell
What are people using C++ for in 2019? Last time I used it was for a Qt
desktop application of all things. I would imagine its main usage is in high
performance or hardware constrained environments these days, but I'm curious
what people are doing with it.

I do a lot of node.js programming, which uses C++ to write extensions, so
here's hoping I rememeber it if/when I need to.

~~~
zelly
high frequency trading, AAA video games, aerospace, compilers, audio, self-
driving cars, search engines, subways

If it's important, it's using C++.

~~~
gpderetta
Subways?!? Tell me more!

