Trip report: Winter ISO C++ standards meeting (Jacksonville)

[Edited to add C++20 schedule at end]

On Saturday March 17, the ISO C++ committee completed its winter meeting in Jacksonville, Florida, USA, hosted with thanks by the Standard C++ Foundation and Perennial. We had some 140 people at the meeting, representing 8 national bodies. As usual, we met for six days Monday through Saturday, including all evenings.

A special highlight was on Thursday evening (the only non-officially-working evening) when Bjarne Stroustrup personally hosted the entire committee for a celebratory dinner to share the 2018 Charles Stark Draper Prize, the U.S.’s top engineering honor, which this year was awarded for a programming language for only the second time in its history. Although the prize was awarded to Bjarne personally, he made it clear that he considered this an award for the whole C++ community, without whom C++ would never have been successful, and so he hosted the dinner for the committee as a representative proxy for the entire worldwide C++ community. — So to all C++ programmers and contributors who are reading this: Thank you, from Bjarne and from us, for your support, and consider yourselves part of this year’s Draper Prize.

The following are some highlights of what we achieved this week. You can find a brief summary of ISO procedures here. The main things to note are:

  • “IS” means “international standard.” In our case, it’s the core C++ standard itself. Think of this as “trunk.”
  • “TS” means “technical specification,” a document separate from the main standard where we can gain experience with new features before putting them into the IS. We have several of these, summarized on the status page. Think of these as “beta branches.”

Leading up to this meeting

As I reported in my previous trip report for the fall meeting (Albuquerque 2017), last time we almost completed addressing the comments received from national bodies in the Modules comment ballot that ran last summer. The rest were addressed in a series of teleconferences between meetings, and the Modules TS was finalized and shipped to ISO at the end of January.

One of the highlights in the pre-meeting mailing was “Direction for ISO C++” (Beman Dawes, Howard Hinnant, Bjarne Stroustrup, Daveed Vandevoorde, Michael Wong). Although non-binding, it’s the first set of recommendations from our recently created advisory Direction Group, a small subgroup of respected long-time participants that currently consists of those paper authors and is chaired this year by Bjarne Stroustrup.

Features adopted for C++20

We adopted several new features into the draft standard.

[[no_unique_address]] (Richard Smith). You know the empty base optimization (EBO)? If you do, can you remember the (probably many) times you’ve artificially made another class a base of your class, instead of just a data member, just so you could get EBO? And, every time that happened, you wished C++ had the empty member optimization (let’s call it “EMO”)? In C++20, it does, and you opt in via [[no_unique_address]]. Here’s an example from the paper:

template<typename Key, typename Value,
         typename Hash, typename Pred, typename Allocator>
class hash_map {
  [[no_unique_address]] Hash hasher;         // EMOji
  [[no_unique_address]] Pred pred;           // EMOji
  [[no_unique_address]] Allocator alloc;     // EMOji
  Bucket *buckets;
  // ...
public:
  // ...
};

[[likely]] and [[unlikely]] (Clay Trychta). (The link is to R2 of the paper, which contains more description. The R4 version is the one that was adopted.) Many compilers already allow you to “hint” whether a branch is likely or unlikely to be true, which can help optimizations. This standardizes that. Here’s an example from the paper:

if (foo()) [[unlikely]] return false;
if (bar()) [[unlikely]] return false;
baz();

Major disclaimer: This feature comes with the same warning label as the existing compiler extensions, which is “measure, measure, measure!” Compilers already know which branches are likely, usually better than you do (especially with profile-guided optimization, aka PGO). A major reason to use this feature is not actually to optimize (though it can help if you don’t have PGO), but to control which path gets optimized for other reasons. For example, for some code it is essential to make the uncommon path faster so that it is faster when you do hit it — and in such cases you would actually use this attribute in the inverted sense, so please also write a comment nearby to document that intent otherwise some hapless reader (more than likely your future self) will be temporarily confused.

Extending <chrono> to calendars and time zones (Howard Hinnant, Tomasz Kamiński). This is a much-loved (and huger-than-you-think) library addition that will help a lot of users, and really exercises modern C++ features like user-defined literals.

span: Bounds-safe views for sequences of objects (Neil MacIntosh, Stephan T. Lavavej). This one comes directly from the C++ Core Guidelines’ Guideline Support Library (GSL), and is intended to be a replacement especially for unsafe C-style (pointer,length) parameter pairs. We expect to be used pervasively as a vocabulary type for function parameters in particular.

Cleanup adopted for C++20

We also made some improvements to existing features.

“Down with typename!” (Nina Ranns, Daveed Vandevoorde). Are you tired of writing typename redundantly in places where the compiler should know only a type was possible? So were the proposal authors. Now typename is required in fewer places.

Lambda capture initializers can now expand variadic parameter packs (Barry Revzin). An example, taken from the paper:

template<class F, class... Args>
auto delay_invoke(F f, Args... args) {
    return [f=std::move(f), ...args=std::move(args)]() -> decltype(auto) {
        return std::invoke(f, args...);
    };
}

The now-allowed expansion is the one in the third line.

Consistent begin/end for range-for (Ville Voutilainen). The range-based for loop is already customizable, and can handle ranges that have both member rng.begin()/rng.end() functions or ones that have non-member begin(rng)/end(rng) functions. But what if it relies on the non-member functions, but happens to also have one member named either begin or end (such as, say, end in ios_base)? That’s now legal, we ignore the one-off member and use the non-member pair. Here’s an example from the paper that is not legal in C++17 but now works in C++20:

struct X : std::stringstream { /*...*/ };

std::istream_iterator<char> begin(X& x)
  { return std::istream_iterator<char>(x); }

std::istream_iterator<char> end(X& x)
  { return std::istream_iterator<char>(); }

int main() {
    X x;
    for (auto&& i : x) {   // works in C++20
      // ...
    }
}

Interesting tidbit: This is one of those “new functionality” features created by removing wording in the standard, namely removing a restriction. The entire wording change was to change “either (or both) finds” to “both find” in one place.

Structured bindings can access accessible members (Timur Doumler). In C++17, you could use structured bindings to bind to class members as long as they were public. But what if you’re inside a member or friend of the class? Shouldn’t you be able to use structured bindings on members, which are visible (i.e., accessible) to you even if they aren’t public to everyone, just like we can do any other normal thing with those members? In C++17 that didn’t work, but it was an oversight and now we can do that:

class X {
    int i;
    int j;
public:
    friend void f();
};

void f() {
    X x;
    auto [myi, myj] = x;   // now ok
}

We also adopted some other fixes, including:

… and a few more including a couple of small extensions to coroutines and networking. Note that those two TSes were already published, and are not yet merged into the C++ draft standard, but we are still maintaining those experimental TS “branches” with fixes and updates, so that those will be done and ready once we are ready to merge those TS branches into the C++ “trunk” project itself.

Other major full committee approvals

We approved Parallelism TS 2 to be extended with the (huge) extensions in Data-parallel vector types and operations (Matthias Kretz) and declared it feature-complete: It is now being sent out for its main ISO comment ballot.

We also decided to officially open a Reflection TS work item, which means that the committee as a whole is taking ownership of the proposal and intends to progress it as a TS. The initial content is from the paper “Static reflection” (Matúš Chochlík, Axel Naumann, David Sankel) but everyone should understand that the surface syntax will change. The primary point of the TS is in the underlying “engine” and functionality, and the intention is to replace the placeholder template-metaprogramming-like reflexpr syntax with an object-like model that looks like “more constexpr code” — regular C++ code that is able to be run at compile time.

Language/library evolution subgroup approvals

Here is a list of proposals that achieved Evolution or Library Evolution working group (EWG or LEWG) design approval. This means that the subgroup responsible for approving the design has done so (sometimes provisionally, with a few “revision is expected” notes below), and the next step is that they now enter wording review in the Core or Library working group (CWG or LWG), and are slated to be proposed for formal adoption in C++20 at a future meeting. Thanks to Olivier Giroux, Ville Voutilainen, Titus Winters for their notes that contributed to this summary.

For contracts, EWG discussed a clarification to what the result of observable side-effects in contract pre/post-conditions is, and the guidance is that it’s undefined behavior.

For reflection and related facilities, EWG approved some papers that are significant milestones for compile-time programming:

EWG also approved:

We also decided to pursue putting in writing two statements about how we evolve C++:

  • EWG decided to pursue turning “C++ Stability, Velocity, and Deployment Plans” (Titus Winters) into a Standing Document, with the expectation is that the document will be revised and reviewed again. Titus Winters will be the main author, and Gabriel Dos Reis, Bjarne Stroustrup, and Mike Spertus will assist.
  • EWG also supports turning “Standard library compatibility promises” (Titus Winters) into a Standing Document, and to add the promises also to the standard’s own Library Introduction clause. Titus Winters will be the main author, with help from Ashley Hedberg, Nevin Liber, Bjarne Stroustrup, James Dennett, Walter E. Brown, Gor Nishanov, Alisdair Meredith, Mike Spertus, Robert Steagall and Daveed Vandevoorde.

We decided to launch a systematic effort to drive out the remaining uses of macros by providing replacements for those uses. We requested an analysis paper listing all the remaining use cases for macros are, a description of the status of the non-macro solutions for those problems, and possible solutions. This paper will be led by Ville Voutilainen, assisted by Bjarne Stroustrup, Gabriel Dos Reis, James Dennett, and Vittorio Romeo.

Somewhat stunningly (to me), we decided to pursue some cleanup to the C fundamental types that would be a breaking change to certain kinds of C and C++17 code. It came up via the discussion of “Towards consistency between <=> and other comparison operators” (Richard Smith), which observed that when we added <=> to C++20, in <=> only we deliberately decided not to repeat the well-known issues that we did not want to perpetuate with C’s two-way comparisons for fundamental types (e.g., signed-unsigned comparison surprises like -1 < 0u giving the “wrong” answer)… which naturally meant that we now have inconsistencies between the preexisting two-way comparison operators and the shiny new three-way <=> operator. When faced with this, the subgroup discovered that we had a consensus in the room that enough really was enough, and we decided to seriously investigate doing some housecleaning and fix those things even though that would include breaking changes to (mostly ill-behaved) C and C++17 code. For example, we are now on a path to pursue deprecating or outright removing the ability to compare two unrelated enumerations (which is just plain suspicious code), and to require -1 < 0u to give the mathematically correct answer even when in the worst case that means generating two comparison machine instructions instead of just one (any code that does such ill-advised things would change from being a correctness problem into “just” a one-extra-instruction performance problem). — We have made no decisions about actually doing this or the ship vehicle for such changes, which likely would have to be rolled out in stages via deprecation followed by removel, and we expect more data to be gathered before Rapperswil regarding how much code could be affected. But as far as I can recall, this is the most breaking-change cleanup to C’s fundamental types that we have ever been willing to seriously consider.

LEWG approved Standard library concepts (Casey Carter). This is the first part of the Ranges TS to be on track for merging into C++20 at an upcoming meeting, and contains the core concepts from the Ranges TS. It is also the first appearance of the concepts language feature in the standard library.

Other progress

Also for concepts, at this meeting EWG approved pursuing a direction based on my paper “Concepts in-place syntax” (Herb Sutter) to have a shorthand syntax for declaring constrained templates.

At this meeting, we considered further improvements to the modules design, including a renewed proposal focusing on a bridge to help existing header-based code move toward a modules-enabled world. By the end of the meeting, the main participants had hammered out a plan to, over the next few meetings:

  • move a core set of modules functionality into C++20 that is “clean” and uncompromised by legacy concerns; and
  • concurrently update the remaining modules TS with features specific to transitioning header-based code to modules, which might include support for macros.

There’s a lot of work remaining, but we’ll know in the next few meetings how the objectives are progressing.

After several years of incubation, executors are now making strong progress and are on track to become a TS in the C++20 timeframe. (Let me explicitly say “thread pools” for the benefit of those who are Ctrl-F’ing to find out how C++ intends to support modern thread pools such as in Windows 10 and Grand Central Dispatch. You’re now in the right place: Modern thread pool support is coming as part of executors.)

Note that there is a dependency on executors before we can merge the networking TS and the future.then feature in the concurrency TS into the C++ draft standard, which means that all of those features are likely to be merged early in the C++23 cycle rather than in C++20.

We are going to try to ship coroutines in C++20.

We are opening a new work item for Library Fundamentals TS3, the third batch of library additions, even as we will soon be starting to fold in material from the recently-published Library Fundamentals TS2 into C++20.

SG15 (Tooling) (Titus Winters) had its first meeting, and there is a shared belief that we need to take concrete steps toward enabling better support for tools for two things in particular: modules, and C++ library package managers. That coincided very nicely with the 2018-02 isocpp.org survey, where on the open-ended question 10, the #1 write-in answer was to request “dependencies / package manager” (15% of all write-ins mentioned that). Clearly there is interest in this area, and it will be interesting to see how this develops into proposals over the coming meetings.

We also created a new study group SG16 (Unicode) with Tom Honermann as the SG chair.

What’s next

Whew! Here is a cheat-sheet summary of our current expectations for some of the major pieces of work that are not already in draft C++20. Note that this is an estimate only.

cpp11147020 - 201803

And here is an updated snapshot of where we are on the timeline for C++20 and the TSes that are completed, in flight, or expected to begin:

wg21-timeline-2018-03.png

Finally, here is the schedule for the C++20 cycle approved by unanimous consent at this meeting:

wg21-schedule-2018-03

Thank you again to the approximately 140 experts who attended this meeting, and the many more who participate in standardization through their national bodies! Have a good spring… we look forward now to our next meetings in June (Rapperswil, Switzerland) and November (San Diego, CA, USA).