Trip Report: C++ Standards Meeting in Issaquah, November 2016

Summary / TL;DR

Project What’s in it? Status
C++17 See below Committee Draft published; final publication on track for 2017
Filesystems TS Standard filesystem interface Published! Part of C++17
Library Fundamentals TS v1 optional, any, string_view and more Published! Part of C++17
Library Fundamentals TS v2 source code information capture and various utilities Voted for publication!
Concepts (“Lite”) TS Constrained templates Published! Not part of C++17
Parallelism TS v1 Parallel versions of STL algorithms Published! Part of C++17
Parallelism TS v2 Task blocks, library vector types and algorithms, context tokens (maybe), and more Under active development
Transactional Memory TS Transaction support Published! Not part of C++17
Concurrency TS v1 future.then(), latches and barriers, atomic smart pointers Published! Not part of C++17
Concurrency TS v2 TBD. Exploring synchronic types, atomic views, concurrent data structures, sycnhronized output streams. Executors to go into a separate TS. Under active development
Networking TS Sockets library based on Boost.ASIO Voted for balloting by national standards bodies
Ranges TS Range-based algorithms and views Voted for balloting by national standards bodies
Numerics TS Various numerical facilities Under active development
Array Extensions TS Stack arrays whose size is not known at compile time Withdrawn; any future proposals will target a different vehicle
Modules TS A component system to supersede the textual header file inclusion model Initial TS wording reflects Microsoft’s design; changes proposed by Clang implementers expected. Not part of C++17.
Graphics TS 2D drawing API In design review stage. No new progress since last meeting.
Coroutines TS Resumable functions First revision will reflect Microsoft’s await design. Other approaches may be pursued in subsequent iterations. Not part of C++17.
Reflection Code introspection and (later) reification mechanisms Introspection proposal undergoing design review; likely to target a future TS
Contracts Preconditions, postconditions, and assertions In design review stage. No new progress since last meeting.

Note: At the time of publication, a few of the links in this blog post resolve to a password-protected page. They will start resolving to public pages once the post-meeting mailing is published, which should happen within a few days. Thanks for your patience!

Introduction

Last week I attended a meeting of the ISO C++ Standards Committee (also known as WG21) in Issaquah, Washington (near Seattle). This was the third and final committee meeting in 2016; you can find my reports on previous meetings here (February 2016, Jacksonville) and here (June 2016, Oulu), and earlier ones linked from those. These reports, particularly the Oulu one, provide useful context for this post.

This meeting was heavily focused on C++17, with a secondary focus on in-progress Technical Specifications, and looking forward to C++20.

At the end of the last meeting, the C++17 Committee Draft (CD) – a first feature-complete draft of the C++17 spec – was sent out for comment from national standards bodies. The comment period concluded prior to this meeting, and as such, the main order of business at this meeting was to go through the comments and address them.

Note that, while the committee is obligated to respond to each comment, it is not obligated to accept the proposed resolution of the comment (if it has one); “there was no consensus for a change” is an acceptable response. (Technically, if a national standards body is unhappy with the response to their comment, it can vote “no” on the final standard, but this practically never happens; the prevailing practice is to respect the consensus of the committee.)

Addressing the CD comments is a process that typically takes two meetings. Indeed, the committee did not get through all of them this meeting; resolution of the comments will continue at the next meeting, at which point a revised draft, now labelled Draft International Standard (DIS) will be published, and sent out for a second round of comments.

C++17

Since the C++17 CD is supposed to be feature-complete, no new features were voted into C++17 at this meeting. See my Oulu report (and things linked from there) for features that were voted into C++17 at previous meetings.

However, some changes to C++17 (that don’t qualify as new features, but rather tweaks or bugfixes to existing features) were voted into C++17 at this meeting, mostly in response to national body comments.

Changes voted into C++17 at this meeting

It’s worth observing that some of these library changes involve taking language changes previously accepted into the CD, such as structured bindings, and making use of them in the library (for example, adding structured bindings for node_handle). Since these types of library changes naturally “lag behind” the corresponding language changes, there have been requests to close the door to new language features earlier than for library features, to give the library time to catch up. No formal decision along these lines has been made, but authors of language features have been asked to give thorough consideration to library impact for future proposals.

Proposed changes to C++17 that were rejected

One notable change to C++17 that was proposed at this meeting was rejected: this introduction of byte type whose intended use was unambiguously “a unit of storage” rather than “a character” or “an 8-bit integer” (which is not true of existing byte-like types such as char or unsigned char). The proposal involved the definition of a library type named std::byte (defined as an enum class), and core wording changes to grant the type special treatment, such as allowing the construction of an arbitrary object into a suitable-sized array of byte, as is currently allowed for char (this treatment is relied upon by the implementations of containers such as std::vector that allocate a block of memory some but not all of which contains constructed objects). The long-term hope is for std::byte to replace char as the type that gets this special treatment, and eventually deprecate (and later) remove it for char.

The proposal to add this type to C++17 failed to gain consensus. This was partly because we’re late into the process (this would have had to be another exception to the “no new features beyond the CD” rule), but also because there were objections to naming the type “byte”, on the basis that there is a lot of existing code out there that uses this name, some of it for purposes other than the one intended in this proposal (for example, as an 8-bit integer type).

It seemed like there is still a chance for this proposal to gain consensus with the type’s name changed form “byte” to something else, but this is unlikely to happen for C++17.

Technical Specifications

In spite of the heavy focus on addressing comments on the C++17 CD, notable progress was also made on Technical Specifications (TS) at this meeting.

The procedure for publishing a Technical Specification is as follows:

  • Once it has completed design and wording review and is considered to be in good enough shape, a Preliminary Draft Technical Specification (PDTS) is published, and sent out for comment by national standards bodies.
  • The comments are reviewed and addressed (much like comments on a C++ Committee Draft)
  • The revised Technical Specification is sent out for final publication. (Optionally, if the committee believes the TS is not ready for publication and needs a second round of comments, it can publish a Draft Technical Specification (DTS) and send it out for comment, and only subsequently publish the final TS. However, this generally hasn’t been necessary.)

At this meeting, two TS’s were approved for being sent out for a PDTS ballot, and one was approved for final publication.

Library Fundamentals TS v2

The Library Fundamentals TS v2 had previously been sent out for its PDTS ballot, and the library working groups had been hard at work addressing the comments over the past few meetings.

At this meeting, the process was finally completed. With a few final changes being voted into the TS (a tweak to the searchers interface and miscellaneous other fixes), the TS was approved for final publication!

Ranges TS

The Ranges TS has passed its initial wording review. It picked up a couple of changes, and was approved to be sent out for its PDTS ballot!

The Ranges TS is unique in that it is, so far, the only TS to have a dependency on another one – the Concepts TS. There is nothing wrong with this; the only caveat is that, obviously, the Ranges TS can only be merged into the C++ standard itself after (or together with) the Concepts TS. Over time, I expect other TS’s in the future to be in a similar situation.

The Ranges TS is also notable for containing the beginnings of what could end up being a “standard library v2” – a refresh of the C++ standard library that uses Concepts and makes some (but not a gratuitous amount) of breaking changes compared to the current standard library. I’m excited to see it move forward!

Networking TS

The Networking TS has also passed its initial wording review. It, too, picked up a couple of changes, and was approved to be sent out for its PDTS ballot!

I’m also quite excited to see the Networking TS move forward. In addition to providing a socket library for C++, it defines foundational abstractions for asynchronous programming in C++. Its design has influenced, and will continue to influence, C++ proposals in other areas such as concurrency and (perhaps at some point in the future) input handling.

Coroutines TS

The Coroutines TS contains the co_await proposal, based on Microsoft’s original design.

As mentioned previously, there are efforts underway to standardize a proposal for a different, stackful flavour of coroutines, as well as an exploratory effort to unify the two flavours under a common syntax. These proposals, however, are not currently slated to target the Coroutines TS. They may instead target a different TS (and if a unified syntax emerges, it could be that syntax, rather than the one in the Coroutines TS, that’s ultimately merged into the C++ standard).

In any case, the Coroutines TS is currently moving forward as-is. A proposal to send it out for its PDTS ballot came up for a vote at this meeting, but failed to gain consensus, mostly on the basis that there has not been time for a sufficiently thorough review of the core language wording parts. Such review is expected to be completed by the next meeting, at which time – if all goes well – it could be sent out for its PDTS ballot.

Concepts TS

To recap the status of the Concepts TS: it was published last year, not merged into C++17, and now has a Working Draft that’s available to accept changes. Whether that Working Draft will eventually be published as a Concepts TS v2, or merged directly into C++20, remains to be decided.

One change was voted into the Concepts Working Draft at this meeting: a proposal to allow a requires-expression to appear in any expression context, not just in a concept definition. This is useful for e.g. using a requires-expression in a static_assert.

There is some uncertainty regarding the longer-term future direction of Concepts. The following areas seem to be somewhat contentious:

  • Definition checking, which I wrote about in a previous post. Definition checking is a feature that was part of the original C++0x Concepts design, and which has long been promised as an eventual extension to the current Concepts Lite design. However, there doesn’t seem to be consensus on how amenable the Concepts Lite design is to definition checking, or at least, what quality of definition checking it is amenable to. In my view, for example, if the definition checking doesn’t have the crucial property that “if a template definition passes the check, then all instantiations of it with arguments that satisfy the constraints will be successful”, then there is little point to the whole exercise. (It’s worth noting that Rust has the equivalent of Concepts (called traits in Rust), and the equivalent of definition checking (the checking that’s performed on generic parameters with trait bounds, to ensure that they’re not used in ways other than what’s allowed by the trait). Definition checking in Rust does have the property I mentioned above – this is why in Rust we don’t see the horrifying long compiler errors with instantiation backtraces that we’ve come to dread in C++.)
  • The proliferation of concept definition syntaxes. The “abbreviated function template” notation (where you get to write a function template that looks like a non-template function, using concept names in place of type names) in particular seems to be somewhat controversial. Allowing this syntax was one of the reasons the proposed merger of the Concepts TS into C++17 was rejected (the other major reason being insufficient implementation and use experience). Based on my conversations with other committee members, I get the impression that this objection is likely to persist the next time Concepts comes up for a vote (for example, for merger into C++20).

Modules TS

The Modules TS has a working paper, which largely reflects Microsoft’s design. It is under active wording review.

The implementers of Modules in clang have a proposal for some design changes based on their implementation experience. It is unclear at this point whether these changes, if approved, would go into the initial Modules TS; some of them, particularly the more controversial ones such as the support for exporting macros, may end up targeting a second revision of the Modules TS instead.

Parallelism TS v2

The Parallelism TS v2 is making good progress. It’s expected to contain task blocks, library vector types and algorithms, and perhaps context tokens. The TS should be ready for a PDTS ballot once wording review of the vector proposal is completed.

Concurrency TS v2

The Concurrency TS v2 (doesn’t have a working draft yet) is also making progress. It’s expected to contain a synchronized output stream facility, atomic_view, a synchronized value abstraction, queues, and counters, possibly among other things.

Executors, which have originally been slated for Concurrency TS v1 but got bogged down in lengthy design discussions over the years, have made notable progress at this meeting: for the first time, the various parties agreed on a unified proposal! This may end up targeting a separate Executors TS, so it doesn’t hold back the Concurrency TS v2.

The chair of SG 1 (the Study Group concerned with parallelism and concurrency) remarked that splitting proposals into “parallelism” and “concurrency” buckets seems to be less useful as time goes on and some topics, such as executors, concern both. It’s possible that these two series of TS’s will be folded together into a single series in the future, released more frequently.

Future Technical Specifications

In addition to the above already-inflight Technical Specifications, a number of new ones are planned for the future.

Reflection

The Reflection Study Group (SG 7) has been reviewing a proposal for static introspection (design, specification). At this meeting, the proposal was approved by SG 7, and sent onward for review by the Evolution and Library Evolution working groups starting at the next meeting. The ship vehicle will be determined by these working groups, but it’s expected to be a TS (the other possibility is C++20).

I write about SG 7’s meeting this week in more detail below.

Numerics

The Numerics Study Group (SG 6) is planning a Numerics TS that will contain a variety of facilities, as outlined here. The initial draft of the TS will likely just be a concatenation of the various individual proposals (which are being developed by various authors; see proposals with “Numerics” as the audience in the list here); the SG 6 chair hopes such an initial draft will be produced at the next meeting.

There was also a proposal to have a separate Technical Specification concerning random number generation, which received no objections.

Graphics

The Graphics TS, which proposes to standardize a set of 2D graphics primitives inspired by cairo, is still under design review. No time was spent reviewing the proposal at this meeting, so there is no new progress to report compared to last meeting.

Evolution Working Group

As usual, I spent my time in the Evolution Working Group (EWG), which spends its time evaluating and reviewing the design of proposed language features.

EWG did two things this week: first, it looked at national body comments on the C++17 CD which touched on the design of the language; and second, it looked at new language proposals, all of which were targeting C++20 or beyond (or a Technical Specification). I’ll talk about each in turn.

National Body Comments

The national body comments can be found in two documents: the official ones, and the late ones which therefore aren’t considered official, but were still looked at. I can’t link to individual comments directly, so I refer to them below by country and number, e.g. “US 1”.

A couple of procedural notes on comment processing:

  • When the C++17 CD was published, the document enjoyed the committee members’ consensus (otherwise it wouldn’t have been published). A change to it at this stage is only considered if it increases consensus, which is a high bar. Comments proposing changes which do not meet this high bar are disposed with the response “there was no consensus for a change”.
  • As the comments originate from a variety of authors, they sometimes ask for contradictory things (sometimes even within a single national body). In such cases, both options are considered, but again, a change is only made if it increases consensus (which is less likely in this scenario).

With that said, here are the comments that were looked at, grouped by the feature they concern:

  • Comments concerning class template argument deduction
    • Implicit deduction guides (GB 21, US 19, US 20)

      To recap, class template argument deduction is a feature where template arguments for a class template can be deduced at construction time, instead of being explicitly specified, like so:

      std::pair p(42, "waldo"s); // deduce std::pair<int, std::string>

      The deduction can be guided either by the constructors of the primary template, which are called implicit deduction guides in this context, or by explicit deduction guides, which are new constructs declared outside the template specifically for the purpose of guiding this sort of deduction.

      The proposal authors analyzed the impact of this feature on the standard library and found that, while in many cases the existing constructors provide the desired deduction behaviour, in some other cases explicit guides would need to be added to complement or correct the behaviour of the implicit ones.

      The comments listed here are concerned with what to do with implicit deduction guides in light of this library impact. One comment proposed removing them altogether, requiring explicit guides to be written in all cases; two others request tweaks to the behaviour of implicit guides.

      EWG expressed a strong preference for keeping implicit deduction guides, but also for adding to the standard library whatever explicit guides are necessary to get desired deduction behaviour for standard library types.

      The proposed behaviour tweaks were accepted. The first proposed that if, for a given constructor call, an explicit guide and an implicit guide are equally good matches, the explicit guide be preferred, instead of resulting in an ambiguity.

      The second tweak was more interesting. It concerned the behaviour of a T&& parameter in a constructor of the primary template. Parameters of the form T&& have the unique property that they behave differently depending on whether or not T is deduced. If T is not deduced, they are always rvalue references (unless T is explicitly specified to be an lvalue reference type); if T is deduced, they are forwarding references (formerly called universal references), which may end up being lvalue or rvalue references. Now, if T is a template parameter of a class, and a constructor of that class has a T&& parameter, normally T is not deduced; but when the constructor is used as an implicit deduction guide, it is! As a result, the semantics of the parameter silently change. To avoid this, a tweak to the rules was made to ensure that the parameter retains its non-forwarding semantics in the implicit guide context.
    • Uniform initialization (FI 21, GB 13, US 94). These comments concerned the fact that, while the feature allows std::pair p(42, 43), std::pair p{42, 43}, and std::pair(42, 43), it does not allow std::pair{42, 43}. EWG agreed that this inconsistency should be fixed, although it did ask for a paper to be written, as specifying this was deemed sufficiently non-trivial.
  • Comments concerning expression evaluation order (CA 18, US 1, US 3, US 93, US 102, Late 4).

    Several of these comments concerned the discrepancy in the order of evaluation between a @= b (where b is evaluated before a, for consistency with assignment) and a.operator=(b) (where a is evaluated before b, for consistency with member function calls). (Note that @ here is meant to stand in for any operator that can be combined with =, such as +=, -=, etc.) This issue was discussed previously, and the comments didn’t really bring any new information to the table; there was no consensus for a change.

    Another comment asked to revisit the decision previously made to have the evaluation of function arguments with respect to each other be unsequenced, and instead evaluate them left-to-right. There was no consensus for a change here, either.
  • Comments concerning decomposition declarations (“structured bindings”)
    • Syntax – [] vs. {} (ES 2, FI 23, US 23, US 71, Late 9, Late 12). The original proposal for decomposition declarations used the syntax auto {a, b, c}; that was changed at the last meeting to auto [a, b, c]. This change was fairly controversial, and several comments asked to change it back to {} (while others encouraged keeping the []). There are technical arguments on both sides (the [] syntax can conflict with attributes once you start allowing nested decompositions; the {} syntax can conflict with uniform initialization if you throw Concepts into the mix and allow using a concept-name instead of auto), so in the end it’s largely a matter of taste. The clang implementers did report that they tried both, and found the ambiguities to be easier to work around with []. In the end, there was no consensus for a change, so the status quo ([] syntax) remains.
    • static, thread_local, constexpr, extern, and inline decomposition declarations (GB 16, GB 17, US 95). There was general agreement that allowing these modifiers is desirable, but the exact semantics need to be nailed down (for example, for constexpr is only the unnamed compound object constexpr, or the individual bindings too?), and EWG felt it was too late to do that for C++17. The comment authors were encouraged to come back with proposals for C++20.
    • Decomposition in init-captures (US 92). EWG considered this an extension, and was open to it, but not in the C++17 timeframe.
    • Discarding values in decomposition declarations (US 100). This was rejected as the topic had been previously discussed.
    • Decomposition declarations and arrays (GB 18). This comment pointed out an inconsistency where decomposition declarations copy arrays by value, but the underlying mechanism used to specify them is template argument deduction, which decays arrays to pointers. The suggestion was to remove the special-case behaviour for arrays in decomposition declaration. Others, however, defended the special case, arguing that not copying arrays by value is a mistake inherited from C, and new features like this are opportunities not to repeat such mistakes. There was no consensus for a change.
    • Explicit types in decomposition declarations (FI 3). This was a request (also accompanied by a paper) to allow explicitly specifying the type of the compound object (and/or of the individual bindings). (As a strawman syntax, consider auto [a : T, b : U, c : V] = expr, where the decomposition is ill-formed if the types of a, b, and c do not match T, U, and V, respectively). EWG was open to an extension along these lines, but not in the C++17 timeframe.
    • Decomposition declarations in parentheses (FI 20). This was a request to allow the form auto [a, b, c](expr) in addition to auto [a, b, c] = expr and auto [a, b, c]{expr}; that was approved.
    • When are get<>() functions called in decomposition declarations? (Late 3). This comment concerned the case where type being decomposed is neither an aggregate strucure nor an array, but a tuple-like user-defined type where the individual bindings are extracted using get<>(). The specification wasn’t clear as to whether these get<>() calls occur “eagerly” (i.e. at the point of decomposition) or “lazily” (at the point of use of the individual bindings, which can potentially mean calling get<>() multiple times for a given binding). EWG decided in favour of “lazy”, because it enabled certain use cases (for example, decomposing a type such as a status/value pair where it’s only legal to access the value if the status has a certain value), while types that do nontrivial work in get<>() (thus making multiple calls expensive) seem rare.
  • Comments concerning default comparisons (ES 7, RU 5, US 5, US 69, Late 7, Late 14). As you’ll recall from my Oulu report, default comparisons failed to achieve consensus to go into C++17. These comments were an attempt to save the feature by putting a less-controversial subset into C++17. There were three specific proposals for doing so on the table:
    • The first proposal concerned only generating operator!= from operator==, and operator>, operator<=, and operator>= from operator<; operator== and operator< themselves still have to be manually defined (although automatic generation of those would be a compatible extension). The proposal also contained a new mechanism for “generating” these derived operators: rather than having the compiler generate what behave like new overloaded functions, expressions of the form a != b are reinterpreted/rewritten to be of the form !(a == b) if a suitable operator!= cannot be found (and similarly for the operators derived from operator<). It was pointed out that this mechanism, like the mechanisms underlying some of the previous proposals, suffers from the slicing problem: if a base class defines both operator== and operator!= (as a class in existing code might) while a derived class defines only operator== (as a class written with this proposal in mind might), then an expression of the form a != b, where a and b are objects of the derived class, will call the base’s operator!= because there is a matching operator!= (and as a result, any data members in the derived class will not participate in the comparison).
    • The second proposal concerned default generation of operator== (but not operator<), based on the following simple rule: if operator= is auto-generated, so is operator==, the idea being that the semantics of assignment and equality are fundamentally entwined (if you make a copy of something, you expect the result to behave the same / be equal). The idea had support, but some people were still concerned about having even == be auto-generated without an explicit opt-in.
    • The third proposal concerned adding an opt-in syntax for asking for any of the comparison operators to be generated by declaring them as = default. This has been previously proposed, and people’s concerns largely mirrored those at the previous discussion.

    None of these proposals achieved consensus for C++17. The main reason had to do with another proposal concerning comparison, which wasn’t slated for C++17. This proposal tried to bring some mathematical rigour to comparison in C++, by observing that some types were totally ordered, while others were only weakly or partially ordered. The proposal suggested an API, based on functions rather than operators, to perform tasks such as a three-way comparison of two objects of a totally ordered type. This got people thinking that perhaps down the line, we could build == and < on top of a three-way comparison primitive (for totally ordered types); this would, for example, enable us to generate an operator<= that’s more efficient than what’s possible today. People liked this future direction, and in light of it, each of the above proposals seemed like a half-baked attempt to rush something into C++17, so the group settled on getting this right for C++20 instead.

  • Comments concerning concepts (US 2). While Concepts was not accepted into C++17, a comment asked that a subset of the proposal, consisting of requires-clauses and requires-expressions, be accepted. EWG had no consensus for making a change here; it was felt that the proposed subset was sufficiently substantial that several of the reasons not to put Concepts as a whole into C++17 still applied to them.
  • constexpr static members of enclosing class type (US 24). This comment concerned the fact that a class cannot contain a constexpr static data member whose type is that class type itself. The comment proposed making this work by deferring the processing of such a data member’s initializer (which is what requires the type to be complete) until the end of the class definition. Doing this in general (i.e. for all constexpr static data members) would be a breaking change, since declarations that occur later inside the class definition can use the data member. However, doing it for a subset of cases, that are currently ill-formed, would work, and some ideas were bounced around about what such a subset could be. (A simple one is “when the data member’s type matches the class type exactly”, but we might be able to do better and cover some cases where the data member’s type isn’t the class type exactly, but still requires the class type to be complete.) EWG encouraged people to work out the details and come back with a paper.
  • There was a comment requesting to rename __has_include (US 104) to have a “less ugly” name, such as has__include. This was rejected because there is existing practice using the name __has_include

New Language Features

Here are the post-C++17 features that EWG looked at, categorized into the usual “accepted”, “further work encouraged”, and “rejected” categories:

Accepted proposals:

  • template keyword in unqualified-ids. This concerns a parsing quirk of C++. When the compiler encounters a name followed by a left angle bracket, such as foo<, it needs to decide whether the < starts a template argument list, or is a less-than operator. It decides this by looking up the name foo: if it names a template (in standardese, if it’s a template-name), the < is assumed to start a template argument list, otherwise it’s assumed to be a less-than operator. This heuristic often works, but sometimes falls down: if you have code like foo<type>(arg), where foo is a template function that’s not visible in the current scope, but rather found by argument-dependent lookup (by being in one of the associated namespaces of arg), then at the time the compiler looks up foo, no template-name is found, so the construct is parsed wrongly. This proposal allows the programmer to rectify that by writing template f<type>(arg); think of the template as meaning “I promise the name that follows will resolve to a template”. This mirrors the existing use of the template keyword when naming a template nested inside a dependent type, such as Base<T>::template nested<U>. Some people had reservations about this proposal resulting in programmers sprinkling template about rather liberally, but the proposal passed nonetheless.
  • Allowing lambdas in unevaluated contexts such as inside decltype(). This came up previously, and the feedback was “we like it, but please make sure appropriate restrictions are in place such that the bodies of lambdas never need to be mangled into a signature”. The author revised the proposal to put in place appropriate restrictions. EWG asked for one more tweak – to exclude the body of the lambda expression from the “immediate context” of an instantiation for SFINAE purposes – and with that tweak passed the proposal.
  • Familiar template syntax for generic lambdas. This will allow writing generic lambdas like []<typename T>(T arg) in addition to [](auto arg). The advantage of the first form is that it can express things the second form cannot, such as []<typename T>(T a, T b). The two forms can be combined as in []<typename T>(T a, auto b); in such a case, the invented template parameters (for the autos) are appended to the explicitly declared ones.
  • Allowing the lambda capture [=, this]. The semantics are the same as [=], but this form emphasizes that the we are just capturing the this pointer, and not the pointed-to object by value (syntax for the latter, [*this], was previously added to C++17). (The question of allowing this change into C++17 came up, but there wasn’t a strong enough consensus for it.)
  • A class for status and optional value. This is a library proposal, meant to be an error handling mechanism for cases where throwing an exception is not possible or not ideal (for example because the absence of a value is commonplace, and exceptions would impose undue overhead). The proposal sailed by EWG on its way to LEWG (the Library Evolution Working Group), mostly to see if EWG was OK with standardizing an alternative to exceptions (it was).
  • Benchmarking primitives. This can be considered a follow-up to the timing barriers proposal which was discussed at the previous meeting and revealed to be unimplementable. The paper proposes two benchmarking primitives which are implementable (with equivalents being widely used in production benchmarking libraries today): touch(), which pretends to write to all bits of an object (to prevent the compiler from using information it might have had about the previous value of the object for optimizations), and keep(), which pretends to read all bits of an object (to prevent the compiler from optimizing the object away on account on no one looking at it). They would be library functions, in the namespace std::benchmark, but the compiler would impart special meaning to them. The choice of names was disputed, but that was left for LEWG to bikeshed. (There was a suggestion to put the functions in a namespace other than std::benchmark on the basis that they could be useful for other applications, such as secure zeroing. However, it was pointed out that these functions are not sufficient for secure zeroing, as the hardware can also play shenanigans such as eliding writes.)

Proposals for which further work is encouraged:

  • Querying the alignment of an object. C++11 gave us an alignas specifier to use on a type or a variable, and an alignof operator to query the alignment of a type; missing is an alignof operator to query the alignment of a variable. In practice implementations already provide this, and this proposal thus standardizes existing practice. The discussion centred around whether alignof x (without parentheses) should be allowed, like sizeof x (the consensus was “no”), and whether alignof((x)) (with double parentheses) should return the alignment of the type of x rather than the alignment of the variable x (mirroring the behaviour of decltype, where decltype(x) returns the declared type of the entity x, whereas decltype((x)) returns the type of the expression x; the consensus here was also “no”).
  • Pattern matching for types. This is a compile-time pattern matching mechanism for types in the same vein as the runtime pattern matching mechanism for values that was proposed earlier. It complements if constexpr in a similar way to how switch (or the run-time pattern matching) complements if. The proposed construct would be usable in a statement, expression, or type context, and would have “best match” semantics (where, if multiple patterns match, the best match is chosen). EWG encouraged further work on the proposal, including exploring the possibility of matching on non-type values and multiple types (you can accomplish either with the current proposal using std::integral_constant and std::tuple, respectively, but first-class support might be nicer).
  • Bitfield default member initializers. The initial version of this proposal allowed the naive syntax, int x : width = init;, by adding some disambiguation rules. At the time, EWG thought the rules would be hard to teach, and asked for a new syntax instead. The proposal was revised, suggesting the syntax int x : width : = init; (notice the extra colon). EWG didn’t like this syntax, nor any of the proposed alternatives (another was int x:[width] = init;), and instead settled on allowing the naive syntax after all, but with different disambiguation rules that avoid any code breakage, at the expense of forcing people who add initializers to their bitfields to sprinkle parentheses in more cases.
  • A unified API for suspend-by-call and suspend-by-return coroutines. As I’ve described in previous posts, two flavours of coroutines are being proposed for standardization in C++ – ones with suspend-by-return semantics (a.k.a. “stackless” coroutines), and ones with suspend-by-call semantics (a.k.a. “stackful” coroutines) – and EWG has expressed an interest in exploring whether the two models can be unified under a common syntax. This is a concrete proposal for such a syntax, taking the form of a library API. Feedback from EWG fell into two main categories. First, there was a question of whether this API is at the appropriate level of abstraction; some felt that a higher-level API that includes the notion of a scheduler may be better (the proposal author posited that such an API could be built on top of this one). Second, some felt that it was starting to become clear that a unified API necessarily comes at the cost of some overhead – depending on the implementation strategy, either compile- and link-time overhead, or runtime overhead – and in light of this, the unification may not be worth it. To elaborate on this point: suspend-by-call semantics gives you certain freedoms that suspend-by-return does not – for example, the ability to write code that’s unaware of whether the functions it calls suspend. The proposed unified API preserves these freedoms, even if a suspend-by-return implementation is used, and this is the source of the overhead.
  • Operator dot, for which there are two proposals on the table.
    • The original proposal almost made C++17, but was booted at the last minute when people realized it failed to specify how operator dot interacts with other user-defined conversions. The authors now have an updated proposal that addresses these interactions.
    • Meanwhile, there’s another proposal, which aims to achieve the same goals via an inheritance-like mechanism. Instead of having the wrapper class declare an operator. that returns the wrapped class, the wrapper class declares the wrapped class as a delegate base, using the syntax class Wrapper : using Wrapped, and provides a conversion operator to access the wrapped object (which is stored as a member, or obtained from somewhere else; it’s not implicitly allocated as part of the wrapper object as it would be with real inheritance). The beauty behind this proposal is that the desired behaviour (“when you access a member of the wrapper object, it resolves to a member of the wrapped object if there is no such member in the wrapper object”) falls naturally out of the existing language rules for inheritance (lookup proceeds from the derived class scope to the base class scope), without having to invent new language rules. As a result, the proposal enjoyed a positive reception.

    Both proposals will be discussed further at the next meeting.

  • Attributes for likely and unlikely branches. These would be standardized versions of the widely implemented __builtin_expect(condition, true) and __builtin_expect(condition, false) constructs, spelt [[likely]] condition and [[unlikely]] condition, and restricted to appearing in the condition of an if-statement. EWG liked the idea, but expressed a preference for putting the attribute on statements, such as if (condition) [[likely]] { ... }; this would then also generalize to other control flow constructs like while and switch.
  • Procedural function interfaces. This paper presents a theoretical framework for statically reasoning about the correctness of a program. Described as a “long-term feature”, the eventual goal is to annotate interfaces in a program with claims/assertions in such a way that a tool can statically prove aspects of the program’s correctness. There is some overlap with contracts: this proposal can be thought of as an alternative to contracts, with more ambitious goals; the author believes unification of the proposals is possible. A notable difference from existing proposals is that, rather than trying to express reasoning about a procedural program in language resembling mathematics, this seeks to “express the mathematical proof of a program’s correctness in a procedural way”.
  • Template deduction for nested classes. Currently, a type like A<T>::type, where T is a template parameter, is a “non-deduced context”, meaning that if a function parameter’s type has this form, T cannot be deduced from the corresponding argument type. (Template argument deduction also comes up in the process of matching class template partial specializations, so this restriction means you also can’t specialize a template for, say, “vector<T>::iterator for all T“). The main reason for this restriction is that in A<T>::type, type can name either a nested class, or a typedef. If it names a typedef, the mapping from A<T>::type to T may not be invertible (the typedef may resolve to the same type for different values of T), and even if it’s invertible, the inverse may not be computable (think complex metaprograms). However, if type names a nested class (and we make the case where an explicit or partial specialization makes it a typedef ill-formed), there is no problem, and this proposal suggests allowing that. EWG’s feedback was mainly positive, but a significant concern was raised: this proposal would make whether type names a nested class or a typedef part of A‘s API (since one is deducible and the other isn’t), something that wasn’t the case before. In particular, in a future world where this is allowed, the common refactoring of moving a nested class out to an outer level and replacing it with a typedef (this is commonly done when e.g. the enclosing class gains a template parameter, but the nested class doesn’t depend on it; in such cases, leaving the class nested creates unnecessary code bloat), becomes a breaking change. The author may have a way to address this using alias-templates; details with forthcome in a future revision of the proposal.
  • Pointers to reference members. It is currently invalid to form a pointer to a reference, which means you can’t have a pointer to a member if that member has reference type. This is inconvenient for the reflection proposal, which allows iterating over the data members of a class and getting a pointer to each; currently, such iteration has to skip over members of reference type. This proposal explores filling that hole by allowing pointers to reference members (without allowing pointers to references in general). EWG was open to the idea, but was concerned about this being a slippery slope and eventually opening the door to things like arrays of references. It was also pointed out that reflection has other options available to it. For example, some have proposed an unreflexpr operator which does the reverse of reflexpr: that is, given a meta-object representing an entity in a program (as obtained by reflexpr, or by navigating the meta-object graph starting from another meta-object obtained via reflexpr), unreflexpr gives you back that entity. This would avoid the need to form a pointer to a reference data member: given a meta-object representing the reference data member, you’d just call unreflexpr on it and use the result in places where you’d dereference the pointer.
  • Implicit move on return from local and function parameter rvalue references. This proposes that when a return-expression names a local or parameter variable of rvalue reference type, the return implicitly move it (currently, if you don’t use std::move, std::forward, or similar, a copy is made, because a named rvalue reference is still an lvalue). This would be a breaking change, but the breakage is likely to be limited to situations where the code is already buggy, or using move semantics improperly. EWG encouraged exploration of the scope of breakage in real-world code.

Rejected proposals:

  • Reconsidering literal operator templates for strings. This is a proposal to allow user-defined literal strings, such as "string"op, where op would get the characters of the string as arguments to a template<char...>. This was originally rejected over compile-time performance concerns (processing many template arguments is expensive), and it was suggested that the proposal be revised with additional machinery for compile-time string processing (which would presumably address the performance concerns). This reincarnation of the proposal argued that literals of this form have a variety of uses unrelated to string processing, and as such requiring accompanying string processing machinery is overkill; however, the underlying performance concerns are still there, and as a result the proposal was still rejected in its current form. It was pointed out that a more promising approach might be to allow arrays (of built-in types such as characters) as non-type template parameters; as such, the string would be represented as a single template argument, alleviating many of the performance issues.
  • A char8_t type for UTF-8 character data, analogous to the existing char16_t and char32_t. This was previously proposed, albeit in less detail. The feedback was much the same as for the previous proposal: consult more with the Library Evolution Working Group, to see what approach for handling UTF-8 data is likely to actually gain traction.
  • Static class constructors. These would be blocks of code associated with classes that run once, during static initialization. EWG found this proposal to be insufficiently motivated, observing that at least some of the problems the proposal aims to solve are addressed by inline variables. It was also observed that the proposal doesn’t solve the issue of order-of-initialization of static objects across translation units; some consider solving that to be a blocker for other advancements in the area of static initialization.
  • Template argument deduction for non-terminal function parameter packs. The motivation here is to be able to write things like template<typename... Args, typename Last> void foo(Args... args, Last last) – basically, pattern-matching on a list of variadic arguments to separate and deal with the last one first. This is currently ill-formed, mostly because it’s unclear what the semantics should be in the presence of default arguments. EWG was disinclined to allow this, preferring instead to address the use case of “get the last element of a parameter pack” with a more general pack indexing facility (one such facility is reportedly in the works; no paper yet).

Other Working Groups

Having sat in EWG all week, I don’t have a lot of details to report about the proceedings of the other groups (such as Library Evolution or Concurrency) besides what I’ve already said above about the progress of Technical Specifications and other major features.

I do have a few brief updates on some Study Groups, though:

SG 7 (Reflection)

SG 7 had an evening session this meeting, during which it reviewed and gave its final blessing to the static introspection proposal, also known as reflexpr after the operator it introduces. This proposal will now make it way through the Evolution and Library Evolution groups starting next meeting.

Being a first pass at static introspection, the proposal has a well-defined scope, providing the ability to reflect over the data members and nested types of classes and the enumerators of enumerations, but not some other things such as members of namespaces. Reflecting over uninstantiated templates also isn’t supported, in part due to difficulty-of-implementation concerns (some implementations reportedly represent uninstantiated templates as “token soup”, only parsing them into declarations and such at instantiation time).

Notably, the proposal has a reference implementation based on clang.

The proposal currently represents the result of reflecting over an entity as a meta-object which, despite its name, is a type (keep in mind, this is compile-time reflection). A suggestion was made to use constexpr objects instead of types, in the same vein as the Boost Hana library. SG 7 was hesitant to commit to this idea right away, but encouraged a paper exploring it.

The facilities in this proposal are fairly low-level, and there is a room for an expressive reflection library to be layered on top. Such a reflection library could in turn use a set of standard metaprogramming facilities to build upon. SG 7 welcomes proposals along both of these lines as follow-ups to this proposal.

SG 13 (Human-Machine Interaction)

SG 13’s main work item, the Graphics TS, is working its way through the Library Evolution Working Group.

The group did meet for an evening session to discuss a revision of another proposal concerning input devices. I wasn’t able to attend, but I understand the main piece of feedback was to continue pursuing harmony with the asynchronous programming model of the Networking TS.

SG 14 (Game Development & Low-Latency Applications)

SG 14 didn’t meet this week, but has been holding regular out-of-band meetings, such as at GDC and CppCon, as well as teleconferences. The group’s mailing list is a good place to keep up with progress in the area.

Next Meeting

The next meeting of the Committee will be in Kona, Hawaii, the week of February 27th, 2017.

Conclusion

C++17 is turning out to be an exciting release of the language, with the most talked-about features including: on the language side, structured bindings, class template argument deduction, and if constexpr; on the library side, the filesystem facilities, and vocabulary types like variant and optional; and on the concurrency side, the parallel versions of the standard library algorithms.

This meeting was spent polishing this feature set in preparation for the C++17 standard’s official release next year.

Meanwhile, we are looking forward to an even more exciting C++20, which may contain features ranging from Concepts, Ranges, and Networking to Modules and Coroutines, with some of these already available as Technical Specifications, or soon to be.

I look forward to continuing to participate in and report on the standardization process!

Posted in c++, programming | Tagged , , | Leave a comment

Trip Report: C++ Standards Meeting in Oulu, June 2016

Summary / TL;DR

Project What’s in it? Status
C++17 See below Committee Draft published; final publication on track for 2017
Filesystems TS Standard filesystem interface Published! Part of C++17
Library Fundamentals TS I optional, any, string_view and more Published! Part of C++17
Library Fundamentals TS II source code information capture and various utilities Resolution of comments from national standards bodies in progress
Concepts (“Lite”) TS Constrained templates Published! Not part of C++17
Parallelism TS vI Parallel versions of STL algorithms Published! Part of C++17
Parallelism TS v2 TBD. Exploring task blocks, progress guarantees, SIMD. Under active development
Transactional Memory TS Transaction support Published! Not part of C++17
Concurrency TS v1 future.then(), latches and barriers, atomic smart pointers Published! Not part of C++17
Concurrency TS v2 TBD. Exploring executors, synchronic types, atomic views, concurrent data structures Under active development
Networking TS Sockets library based on Boost.ASIO Wording review of the spec in progress
Ranges TS Range-based algorithms and views Wording review of the spec in progress
Numerics TS Various numerical facilities Under active development
Array Extensions TS Stack arrays whose size is not known at compile time Withdrawn; any future proposals will target a different vehicle
Modules TS A component system to supersede the textual header file inclusion model Initial TS wording reflects Microsoft’s design; changes proposed by Clang implementers expected. Not part of C++17.
Graphics TS 2D drawing API Design review in progress
Coroutines TS Resumable functions Initial TS wording reflects Microsoft’s await design; changes proposed by others expected. Not part of C++17.
Reflection Code introspection and (later) reification mechanisms Introspection proposal undergoing design review; likely to target a future TS
Contracts Preconditions, postconditions, and assertions Design review in progress. Not part of C++17.

Introduction

Last week I attended a meeting of the ISO C++ Standards Committee (also known as WG21) in Oulu, Finland. This was the second committee meeting in 2016; you can find my reports on previous meetings here (October 2015, Kona) and here (February 2016, Jacksonville), and earlier ones linked from those. These reports, particularly the Jacksonville one, provide useful context for this post.

This meeting was sharply focused on C++17. The goal of the meeting was to publish a Committee Draft (CD) of the C++17 spec. The CD is the first official draft that’s sent out for comment from national standards bodies; that’s followed up by one or more rounds of addressing comments and putting out a new draft, and then eventual publication.

The procedure WG21 follows is that the spec needs to be feature-complete by the time the CD is published, so that national standards bodies have adequate opportunities to comment on the features. That means this was the last meeting to vote new features into C++17, and consequently, all committee subgroups were focused on finishing work on C++17-bound features. (The Evolution and Library Evolution groups did have a chance of review some post-C++17 proposals as well, which I’ll talk about below.)

Work on Technical Specifications (TS’s) continued as well, but was noticeably muted due to the focus on C++17.

C++17

As I mentioned, this meeting was the “feature complete” deadline for C++17, so by now we know what features C++17 will contain. Let’s see what made it:

Features already in C++17 coming into the meeting

See my Jacksonville report for features that were already voted into C++17 coming into the Oulu meeting.

Features voted into C++17 at this meeting

Features that didn’t make C++17

In my Jacksonville report, I talked about several features that were proposed for C++17 at that meeting, but didn’t make the cut: Concepts (available instead as a published Technical Specification), Coroutines (targeting instead a work-in-progress Technical Specification), and unified function call syntax (abandoned altogether, at least for now).

At this meeting, a few additional features originally targeting C++17 were axed.

Default Comparisons

I predicted in my last report that default comparisons might turn out to be controversial, and it turned out to be quite so.

Concerns raised about this fell into several broad categories:

  • Some felt that automatically generating operator== and operator!= made conceptual sense, but generating operator< and its counterparts (operator>, operator<=, and operator>=) did not.
  • Some disliked the opt-out nature of the proposal (that you get the operators by default, and have to opt out if you don’t want them), and expressed a preference for an opt-in proposal (that you don’t get the operators by default, but can opt into them if you’d like). It was pointed out that the last time this preference was polled (at the November 2014 meeting), opt-in had a stronger consensus. (Why did the committee subsequently pursue an opt-out approach, then? I believe it was simply because the opt-out crowd continued to present updated versions of their proposal, while the opt-in crowd let their proposal languish. EWG then expressed consensus for the only proposal on the table – the opt-out one – over nothing at all.)
  • Several people in the Library groups expressed concern that they did not have an opportunity to assess the impact on the standard library, and make changes to standard library classes (such as adding opt-out declarations for relevant types) that might be necessary.
  • There were concerns that automatic generation of operator< meant that subsequent changes to the order of declaration of class members would change the semantics of the comparison.
  • There were concerns that the semantics of the generated operator< and its counterparts, were not a good fit for the low-level model of the language. The details here are a bit sublime (see the proposal wording if you’re interested, particularly around operator<=), but the gist is that the generator operators don’t behave exactly the same as a hand-written function would have in some respects.

As a result of the above concerns, the proposal did not gain consensus to go into C++17.

Most of the objections were to operator< and its counterparts; operator== and operator!= were, by comparison (no pun intended), relatively uncontroversial. The question of just moving forward with the operator== and != parts thus naturally came up. However, this met opposition from some who felt strongly that the two parts of the feature belonged together, and in any case there was no time to formulate a subsetted proposal and assess its implications. The feature thus missed the C++17 train altogether.

I fully expect default comparisons to come back for C++20, though perhaps with aspects of the design space (such as opt-in vs. opt-out) revisited.

Operator Dot

Operator dot also attracted a fair amount of controversy. Among other things, a late-stage alternative proposal which presented some concerns with the original design and offered an alternative, was brought forward.

In the end, though, it wasn’t these concerns that defeated the original proposal. Rather, wording review of the proposal revealed some design issues that the proposal authors hadn’t considered. The issues were related to how operator dot invocations fit into conversion sequences – when are they considered, relative to base-to-derived conversions, other standard conversions, and user-defined conversions. It was too late to hash out a consistent design that answered these questions “on the spot”, so the proposal was withdrawn from consideration for C++17.

I expect this, too, will come back for C++20, with the alternative proposal as possible competition. [Update: I’ve since seen Herb Sutter’s trip report, where he hints that operator dot may in fact come back for C++17, by means of a national body comment on the C++17 Committee Draft asking that it be included. This way of sneakily adding features into a C++ release after the official feature-complete deadline sometimes works, but the bar is high and of course there are no guarantees.]

(It’s worth keeping a mind that there is yet another proposal for operator dot, which was handed to the Reflection Study Group, because it was sufficiently powerful to serve as the basis for a full-blown code reification mechanism. There remains a minority who believe that all other operator dot proposals should be put on hold while we wait for the Reflection Study Group to get to developing that.)

Other Languages Features
  • Removing exception specifications. This was not controversial, the Library Working Group just ran out of time before it could finish reviewing the library parts of the wording for this.
Library Features
  • joining_thread, a proposed wrapper around std::thread whose destructor joins the thread if it’s still running, rather than terminating the program. A concern was brought forward that use of such a wrapper without sufficient care could lead to deadlocks and other more-subtle-than-termination misbehaviour. As a result, the proposal lost consensus to move forward. I personally don’t view this as a great loss; it’s straightforward for users to write such a wrapper themselves, and its absence in the standard library might prompt a prospective user to do enough research to become conscious of things like the deadlock issue that they otherwise may have overlooked.
  • Global swap() accepts unequal allocators. This proved to be controversial during discussions in the library working groups, and was postponed for further study post-C++17.
  • Generalize some sorting algorithms to more iterator types. This was postponed as well due to implementers preferring to have a chance to gain more experience with it.

Towards Publishing C++17

I mentioned that the primary goal of the meeting was to publish the Committee Draft or CD of C++17 for comment by national standards bodies. This goal was accomplished: the Committee voted to publish the C++17 Working Draft, with the approved proposals listed above merged into it, as the CD. (An updated Working Draft that includes the merges will be forthcoming within a few weeks of the meeting.)

This means C++17 is on track to be published in 2017! The “train” (referring to the 3-year release train model adopted by the Committee after C++11) is on schedule🙂

What’s the status of other big-ticket features?

The features below weren’t in the limelight at this meeting, since they were previously decided not to target C++17, but as they’re very popular, I’ll give a status update on them all the same.

Concepts

The Concepts TS was published last year, but was not merged into C++17. What does that mean going forward? It means it has a Working Draft, available to accept fixes (and in fact one such fix was voted in at this meeting) and larger changes (one such larger change was already proposed, and more are expected in the near future).

This Working Draft can eventually be published in a form of the Committee’s choosing – could be as a Concepts TS v2, or merged into a future version of the International Standard (such as C++20).

Coroutines

Coroutines are targeting a Technical Specification which is still a work in progress. The initial contents of the TS are set to be the latest draft of Microsoft’s co_await proposal, but there are also efforts to generalize that into a form that can also admit other execution models, such as “stackful” coroutines. EWG looked briefly at this latter proposal, but otherwise no notable progress was made; everyone was busy with C++17.

Modules

Modules is in a similar state to Coroutines: there’s a proposal by Microsoft which is slated to become the initial content of a Modules TS, and there are proposed design changes pending resolution. As with Coroutines, no notable progress was made this week, the focus being on C++17 features.

Reflection

Reflection continues to be actively worked on by the Reflection Study Group, which met this meet to review the design of its chosen static introspection proposal; I talk about this meeting below.

Evolution Working Group

As has become my habit, I sat in the Evolution Working Group (EWG) for the duration of the meeting. This group spends its time evaluating and reviewing the design of proposed language features.

As with all groups, EWG’s priority this meeting was C++17, but, being “ahead in the queue” of other groups (language proposals typically start in EWG and then progress to the Core Working Group (CWG) for wording review, and if appropriate, the Library groups for review of any library changes in them), it also had time to review a respectable number of C++20 features.

I’ll talk about the C++17-track features first. (Being listed here doesn’t mean they made C++17, just that they were considered for it; see above for what made it.) In most cases, these were features previously approved by EWG, which were revisited for specific reasons.

  • Default comparisons. EWG looked at this proposal on three different occasions.

    First, the authors proposed removing the anti-slicing provisions added last time around (which would have made it ill-formed to slice an object during comparison and initialization), because implementation experience revealed that this broke too much code; this change was approved.

    Second, during CWG review of this feature, implementers expressed a preference for not requiring a diagnostic for the rule that says it’s ill-formed for a comparison of the same two types to resolve to a default-generated comparison operator at one point in a translation unit, and to a user-provided comparison at a later point; EWG rejected tis request, expressing a strong preference for requiring a diagnostic. (For what it’s worth, I fall strongly on the “require a diagnostic” side in this and similar situations. I’ve seen it happen too many times where a C++ programmer is bitten by implementation divergence regarding the diagnosis of a rule that the standard proclaims is “ill-formed; no diagnostic required”. I think we should vigorously limit this style of rule to situations where basically all implementations agree that the rule is prohibitively expensive to diagnose, and thus will not in practice diagnose it.)

    Finally, EWG looked at a proposal to restrict the default generation to operator== and != only, which became a general discussion of the feature, during which many of the concerns mentioned above were articulated. EWG considered several changes in direction, including dropping the default generation of operator< and counterparts as suggested, and moving to an opt-in approach, but neither of these gained consensus, and the unmodified design was submitted for a vote in plenary (which then failed, as I related above).
  • Operator dot came up in EWG twice.

    First, the group briefly clarified the name lookup semantics associated with types that have an operator dot. It was stressed that the guiding model for such types is that of smart references, and so reference semantics are emulated when possible. It was also clarified that operator dot does not capture sizeof (that is, sizeof(my_smart_reference) still returns the size of the reference wrapper type, and not of the referred-to type).

    Second, CWG sent the feature back to EWG to clarify the intended interaction with other types of conversions. During the resulting discussion, it was discovered that there are entire aspects of the design space that haven’t been nailed down yet in this area (specifically, in where applications of operator dot fit into conversion sequences), and that it’s too broad of an area to nail down on the spot. The proposal was therefore withdrawn for revision until the next meeting (and therefore withdrawn from C++17).

    The alternative proposal for operator dot that was newly submitted for consideration at his meeting wasn’t looked at. It wouldn’t have made C++17 even if chosen, so looking at it wasn’t a priority. The authors plans to refine it and hopefully present it at the next meeting.
  • EWG briefly looked at an interaction between if constexpr and generic lambdas. The source of the problem is the semantics of default captures for generic lambdas. C++ says that if a lambda has a default capture, then a variable named inside the lambda is covered by the capture only if the the occurrence of the name is an odr-use (this is a term of art that roughly means “a use requiring the variable to have allocated storage and an address”); however, for a generic lambda, whether a use of a name is an odr-use can depend on the arguments you’re calling the lambda with. This leads to an interaction with if constexpr where determining captures can require instantiating a branch of code whose instantiation would otherwise have been disabled by an if constexpr, leading to an undesirable hard error. EWG’s suggestion was to revise the default capture rules for generic lambdas, perhaps to always require named variables to be captured. (Meanwhile, the if constexpr proposal itself isn’t held up over this or anything.)
  • Two aspects of the inline variables proposal were revisited.

    First, in Jacksonville, a restriction was added that namespace-scope variables could only be inline if they were const; this was meant to discourage mutable global state. It was pointed out that this can be worked around in several ways (for example, by making the variable a reference to a mutable object, or by making it a variable template, which has no such restrictions). Rather than trying to stymie these workaround approaches, EWG decided to just lift the restriction, making the feature simpler.

    Second, EWG previously asked that constexpr imply inline. CWG pointed out that for namespace-scope variables, this would change the linkage of existing constexpr variables, breaking existing code. As a result, for namespace-scope variables, constexpr no longer implies inline (for static data members of classes, it still does, because there is no linkage issue there).

    A minority continued to oppose this proposal altogether, but they were overruled.
  • Template argument deduction for class templates came back to EWG because CWG pointed out a snag. The proposal allowed for “partial deduction”, which meant that you could provide a partial template argument list to a class template when declaring a variable, and have the remaining template arguments be deduced from the constructor arguments. For examle:

    template <int N, typename T> struct small_vector { small_vector(T fill); };
    small_vector<3> v(42); // N is specified, T is deduced

    However, it was pointed out that in the presence of variadic templates, the “partial” argument list could also form a valid type in and of itself:

    tuple<string> t("waldo", 42, 2.0f);

    EWG felt it would be surprising for this to deduce tuple<string, int, float> given that tuple<string> is also a valid type.

    A suggestion was raised to force the caller to provide all template arguments, but use auto for the ones that should be deduced:

    tuple<string, auto, auto> t("waldo", 42, 2.0f);

    however the details remained to be pinned down, and EWG felt uncomfortable standardizing this approach on the spot, instead preferring to disallow partial deduction. Therefore, the feature is now restrited to the case where no template argument list is provided:

    tuple t(std::string("waldo"), 42, 2.0f); // all arguments deduced

  • template <auto N> was briefly revisited to resolve an issue where certain code examples involving deduction of a non-type template parameter from an array bound would become ambiguous. EWG requested that the deduction rules be tweaked to avoid introducing the ambiguity, at the expense of making the already complicated deduction rules even more so; see the paper for details.
  • A few design points about structured bindings came up for discussion.

    The most prominent issue was the choice of customization points for a non-aggregate user-defined type to opt into the mechanism. The current specification requires using the customization point for “tuple-like” types – that is, specializing std::tuple_size to return the number of elements, std::tuple_element to return the type of each element, and std::get to return a reference to each element. Several people, including the author of this paper, expressed a desire to have a customization point that’s more specific to this feature, and/or one that operated by ADL rather than by specialization. EWG was sympathetic to this, but believed that “tuple-like” should be at least one of the customization points (for consistency with operations like std::tuple_cat()), and that it’s good enough as the only customization point in C++17; the Library Evolution Working Group can then design a nicer customization point in the C++20 timeframe.

    The handling of bitfield elements also came up. The proposal specifies that the bound variables act like references to the elements of the structure, but you cannot form a reference to a bitfield. However, the customization point mechanism allows for std::get to return a proxy type that assigns through to the bitfield element; this was deemed a good enough solution until the problem of not being able to form a reference to a bitfield is addressed more comprehensively by the core language.
  • A new proposal for if statements with an initializer.

    The background to this proposal is that C++ already allows you to declare a variable in the condition of an if statement if the variable’s type is contextually convertible to bool. For example, you can do this:

    if (Type* foo = GetFoo()) {
    ...
    }

    Here, the body of the if statement will execute if foo is not nullptr.
    The advantage of doing this over declaring foo above the if statement is that the scope of foo is limited to the if statement (including any else block).

    However, often you have a type which is not contextually convertible to bool, but you still want to check something about it, and only use it if the check passes. This proposal allows you to do this while keeping the variable’s scope local to the if, by combining a declaration with an expression to test:

    if (Type foo = func(); foo.isOk()) {
    ...
    }


    EWG really liked this, so much that they made an exception to the previously-agreed rule that new features first proposed at this meeting wouldn’t be considered for C++17. Two small modifications were requested: that the feature work for if constexpr and switch as well.

  • Modernizing using-declarations, which allows a pack expansion to occur in a using-declaration. This was another brand new proposal that EWG made an exception for and approved for C++17, but unfortunately CWG did not have time to review the wording, and it thus did not make it in.

Now let’s move on to the C++20-track features. I’ll categorize these into my usual “accepted”, “further work encouraged”, and “rejected” categories:

Accepted proposals:

  • Comma omission and comma elision, a proposal to solve a long-standing issue with the preprocessor where it was very difficult to tell apart zero argument from one argument in a variadic macro (because macro arguments are delimited by commas, and zero arguments and one argument both have the property that they have no commas). Importantly, the author has run this by WG14 (the C Standards Committee), and they like the direction and would be open to adopting it in tandem with C++ – an important consideration because WG21 tries to avoid preprocessor divergence between C and C++ where possible.
  • A proposal to clean up an obscure corner of the type system, dubbed abominable function types. EWG left the specific cleanup approach up the discretion of the authors and CWG.
  • A proposal to define the semantics for certain new parallel execution policies, vector and wavefront policies. EWG sent this to CWG, with the caveat that compiler backend implementers should be present during the CWG review (as they would be involved in the implementation of such policies).
  • Designated initializers. This is a C feature that allows you to initialize a structure with a braced-init-list whose elements (“designators”) name the fields, like so:

    struct Point { int x; int y; };
    void foo(Point);
    ...
    foo({ .x = 2, .y = 3});

    The proposal was to adopt this feature into C++, with several important modifications, the most important one being that the order of the designators must match the declaration order of the fields.

    This solves, at least partially, one of the longest-standing incompatibilities between C and C++.

Proposals for which further work is encouraged:

  • Regular void, a proposal to remove most instances of special-case treatment of void in the language, making it behave like any other type. The general idea enjoyed an increased level of support since its initial presentation two meetings ago, but some details were still contentious, most notably the ability to delete pointers of type void*. The author was encouraged to come back with a revised proposal, and perhaps an implementation to help rule out unexpected complications.
  • Return type deduction and SFINAE, which aims to solve the problem that if a function uses C++14 return type deduction, the return expression is no longer in the immediate context of the call, and so errors in the return expression become hard errors rather than substitution failures. (By contrast, in C++11, the return expression would typically appear in the signature as decltype(return-expr), bringing it into the immediate context of the call.) The proposed solution is to extend SFINAE to function bodies in certain contexts, with some important limitations to avoid some of the problems with extending SFINAE to function bodies in general (such as the need to mangle the function’s body into the name).

    As expected, implementers were quite wary to extend SFINAE; they were cautiously open to some form of limited extension, but the precise limitations remain to be nailed down. The author was encouraged to continue discussing this with a wide variety of compiler implementers, to arrive at a solution that everyone was on board with.
  • A [[visible]] attribute, intended to be a standard version of things like __declspec(dllexport) and __attribute__((visibility("default"))). EWG recognized that there’s a widespread desire for something like this, but also noted that interactions with Modules should be considered, and suggested further exploration of the problem space.
  • Product type access. This is a proposed extension to structured bindings that would expose the mechanism by which an aggregate structure type is decomposed into its fields to user code, by having such structures “automagically” implement the customization point used to opt non-aggregate user-defined types into structured binding. EWG agreed that this is desirable, but preferred to wait until the design of that customization point is nailed down in the C++20 timeframe (see above for more discussion of this).
  • Overload sets as function arguments, which allows passing an overloaded name (that is, a name that resolves to a function template, or to a set of overloaded functions and/or function templates) as argument for a function parameter whose type is a type template parameter; the compiler “packages” the name into a function object with a call operator whose body dispatches the call to the overload set. You can write such a function object today (along the lines of [](auto... args){ f(args...); }), but this proposal would allow you to just write f instead.

    EWG liked the proposal, but recognized an important problem. In the case where f resolves to a single, non-template function, you can pass it as an argument today, and it becomes a pointer to the target function. Changing this (to “package” f into a function object as in the case where it’s an overloaded name) would break existing call sites, so the proposal restricts the “packaging” to the case where it is in fact an overloaded name. But this means that, for a given call site that passes f, whether or not it gets “packaged” depends on how many declarations of f are in scope at the call site. As argued in this paper, this can depend on what headers are included prior to the call site, which can vary from one translation unit to another, making it very easy to get into ODR violations. EWG agreed that to avoid this, a new syntax is necessary: []f will always package the name f into a function object, no matter how many declarations of f are in scope (a plain f, meanwhile, will retain its existing meaning of “function pointer if f is a single non-template function, ill-formed otherwise”).
  • Generalized member pointers, which proposes three extensions to C++’s pointers to members: upcasting the member’s owning type (assuming the target of the cast is a non-virtual base); forming pointers to members of members; and forming pointers to bases. EWG liked these extensions, and requested that the author confirm implementability on major compilers, and come back with wording. A fourth extension, to recover a pointer to the object from a pointer to a member of the object, was deferred, to be pursued as a separate proposal. It was pointed out that the first three features could conceivably be extended to pointers to member functions (albeit non-virtual ones) as well.
  • Bitfield default member initializers, which proposes a syntax for giving bitfield members a C++11-style default member initializer (something that’s currently forbidden). The challenge here is to find a syntax that combines the bitfield width specifier and the default member initializer in a way that’s not ambiguous. This specific proposal tried to avoid introducing new syntax, instead just introducing disambiguation rules, but EWG felt the proposed rules were unintuitive, and suggested the author try inventing new syntax instead.
  • Comparing virtual methods. This is not a proposal, just a statement of a problem, namely that sometimes you want to efficiently check whether a class instance has a particular function in its vtable, but the language doesn’t currently provide a way to do this without incurring the full overhead of a virtual function call. EWG encouraged the author to pursue a solution.
  • Lambdas in unevaluated context, which proposes to lift the restriction that lambdas cannot appear inside a decltype(). EWG approved of the intent, but the exact rules need nailing down to ensure that we don’t allow situations that would require mangling a lambda expression into a symbol name.
  • Language support for heterogeneous computing. The language changes for which feedback was specifically solicited mostly concerned the use case of a host device sending code in the form of a lambda to be run on a special-purpose device such as a GPU or accelerator. To this end, the standardization of various aspects of the representation of such lambdas was proposed, so that code on the two devices, potentially compiled by different compilers, can interoperate. EWG’s feedback was to leave these representational aspects up to the implementation; the implication is that, if the host code and the device code are in fact compiled by different compilers, those compilers need to agree amongst themselves (much like how linking code from different compilers together requires that they agree on an ABI).

    The broader proposal to support heterogeneous computing in standard C++ is based on SYCL; it was suggested that the authors also look at CUDA.
  • Pattern matching and language variants is an ambitious proposal to add a first-class pattern matching facility to the language, which can, among other things, deconstruct sum and product types; customization points to opt user-defined sum and product types into pattern matching; and a variant type built into the language (which models a sum type).

    EWG had two main pieces of feedback: first, that you should be able to write patterns that match specific derived types when the input is a base type (relevant prior work on that can be found here); and second, that use of the pattern matching facility should not come with a performance penalty.

    It’s important to note that the proposed built-in variant type would not supersede std::variant, which was standardized at this meeting. It would have named alternatives, which means it would be to std::variant as structs are to std::tuple.
  • Contracts, which provides a way to express preconditions, postconditions, and assertions in the language. The general direction of the proposal was approved at the last meeting; the discussion today mostly concerned details. For example, it was pointed out that specifying the different contract checking modes will be tricky, as there is no precedent in the standard for specifying things that are in practice controlled by compiler flags. Some argued that requiring every declaration of a function to state the pre- and post-conditions is too strict, and having them on the first declaration should be sufficient; in particular, EWG didn’t want contracts to become a de facto part of the type system the way exception specifications have. Finally, some details, such as when postconditions are checked relative to local destructors running, remain to be nailed down.
  • An updated version of the proposal to unify stackful and stackless coroutines under a common model and common syntax was presented. The idea is that the new syntax can be lowered to the same low-level “stackless” representation as the co_await syntax, and thus can have the same performance characteristics (for example, avoiding dynamic memory allocation in many cases), but can also be used in a stackful way when the flexibility offered by that (for example, the ability to suspend from inside code that the compiler hasn’t transformed into a coroutine representation) is desired. The machinery that would enable this to work is that the compiler, guided by “suspendable” annotations, would compile a function either normally, or into a coroutine representation (or both), much as how in the Transactional Memory TS, the compiler can create transaction-safe and transaction-unsafe versions of a function. The usual questions of whether such “suspendable” annotations are part of a function’s type, and what the impact of this bifurcation of the set of generated functions on binary size and linking time is, came up. The conclusion was that the area needs more exploration, and implementation experience would be particuarly helpful.
  • Parameter packs outside of templates, an early-stage proposal to expand the functionality of parameter packs to act as a general type list facility at compile-time, and as a building block for a tuple of values at runtime. EWG liked the goals and use cases, but expressed a desire for a cleaner syntax (the syntax proposed in the paper has ... tokens sprinkled around fairly liberally). It was also pointed out that the proposal has the potential to bring significant compile-time gains by reducing the amount of metaprogramming required to achieve common tasks, and care should be taken to ensure this potential is realized to its fullest extent.
  • File literals, a new type of literal that would name a file, and evaluate to the contents of the file. The main motivating use case is embeddeding external resources (files) into an executable and making it available to the program code in a portable way. Discussion revealed that this feature would be quite a bit more powerful than necessary to achieve this use case, as the contents of the file would be made available for compile-time processing. EWG preferred to avoid this without compelling motivation, and suggested the author formulate the feature as a new type of declaration whose initialization loads the file content at runtime / program load time.

Rejected proposals:

  • Comparison operators in fold-expressions, which proposed to disallow fold-expressions of the form a <... b, because their expansion (a_1 < a_2 < ... < a_n < b if a is the pack) is almost certainly not what the user wants (in C++, a < b < c means “compare a and b, and then take the boolean result of that comparison and compare it to c“, not (a < b) && (b < c)). EWG’s view was that we don’t gain much by disallowing them; what we’d really want to do is specify them to do the sensible thing, but we can’t do that without also changing what a < b < c means (because consistency), and it’s too late to change that (because backwards compatibility).
  • Proposals to make aggregate types hashable and swappable by default. These were withdrawn by the author, in favour of library solutions building upon the extension mechanism provided by structured bindings.
  • An [[exhaustive]] attribute for enumerations, which tells the compiler this is an enumeration whose instances should only take on the value of one of the specified enumerators (as opposed to an enumeration that functions as a bit vector, or an enumeration whose set of values is meant to be extended by the user), and thus guides compiler diagnostics. EWG pointed out that most enumerations are exhaustive, and we want to be annotating the exception, not the norm. However, there wasn’t much appetite for a “non-exhaustive” annotation, either; implementers were of the opinion that current heuristics for diagnostics for switch statements on enumerations are sufficient.
  • Making pointers to members callable. This would have allowed a pointer-to-member-function pmem to be called as pmem(obj, args) in addition to the current obj.*pmem(args). There was no consensus for making this change; the opposition was mainly over the fact that this looked like a step towards unified function call syntax, which was rejected at the last meeting (even though it was pointed out that this proposal is rather unlike unified call syntax, as it does not change any lookup ryules).
  • Allowing any unsigned integral type as parameter type for literal operators, instead of just unsigned long long. This was rejected, mostly because no one could remember what the original reason was for the restriction, and people were hesitant to move forward without knowing that.
  • A new char8_t character type to represent UTF-8 data. EWG was of the opinion that this would be doable, but it would come with some cost (for example, it would be an ABI-breaking change for code that currently typedefs char8_t to be (unsigned) char, similar to how the introduction of the C++11 char16_t and char32_t types was; there is also code in the wild that uses char8_t as a completely different kind of type (e.g. an empty “tag” structure), which would break more severely). The suggested way forward was for the Library Evolution group to decide on a strategy for handling UTF-8 data (perhaps the answer is “just use std::string“, in which case no language changes are needed), and then see what the language can do to help accommodate that design.
  • const inheritance, a new form of inheritance that would allow the derived class to access the base class only through a const reference. EWG did not find this change to be sufficiently motivated.
  • Partial classes, an attempt to solve the problem of a header file containing a class declaration needing to include declarations of types used in private data members and functions, by splitting out a public interface from a class declaration, and allowing most uses of the class with just the interface declaration being included. EWG found several problems with the mechanics of the proposal, and pointed out that Modules, while not solving this problem directly, should address the ultimate goal (reducing compile times) sufficiently.
  • Timing barriers, which attempted to address an interesting problem. In the following code:

    auto start = std::chrono::high_resolution_clock::now(); // #1
    operation_to_be_timed(); // #2
    auto end = std::chrono::high_resolution_clock::now(); // #3

    there is nothing that currently prevents the implementation from re-ordering the statements such that e.g. #1 happens after #2, rendering the code useless. The proposal attempted to introduce a mechanism that would prevent such a re-order, but it was pointed out that such a mechanism is basically unimplementable without completely tying the optimizer’s hands. The reason is explained very nicely in this StackOverflow answer, but to summarize: conceptually, clock::now() observes the current time; to make sure that a particular operation X is not re-ordered with clock::now(), that operation needs to be annotated as modifying the current time ; but every operation “modifies the current time” by taking time to run, so every operation would need to be so annotated. That same StackOverflow answer points to some practical ways to solve this problem.
  • A different take on unified call syntax, where the unified call semantics is opted into on a per-callsite basis, by changing the syntax of the call site to prefix the function name with a dot (.). EWG felt that having to modify call sites defeated the purpose.

There were a few C++20-track proposals that weren’t looked at because no one was present to champion them, or because there was no time. They’ll be picked up in due course.

Library / Library Evolution Working Groups

As I’ve been sitting in EWG for the week, I didn’t have a chance to follow the library side of things very closely, but I’ll mention some highlights.

First, obviously the Library Working Group (LWG) has been quite busy reviewing the wording for the variety of library proposals voted into C++17 at the end of the meeting. A particularly notable success story is variant being standardized in time for C++17; that proposal has come a long way since two meetings ago, when no one could agree on how to approach certain design issues. (There are still some who are unhappy with the current “valueless by exception” state, and are proposing inventive approaches for avoiding it; however, the consensus was to move forward with the current design.)

A notable library proposal that was pulled from C++17 is joining_thread, for reasons explained above.

The Library Evolution Working Group (LEWG) mostly looked at post-C++17 material (see here for a list of proposals). LEWG’s view on ship vehicles has shifted a bit; until recently, most proposals ended up targetting a Technical Specification of some sort (often one in the Library Fundamentals series), but going forward LEWG plans to target the International Standard directly more often. As a result, a lot of the proposals reviewed at this meeting will likely target C++20.

There are also various library Technical Specifications in flight.

The Library Fundamentals TS v2 has had a draft sent to national standards bodies for comment, and now needs these comments to be addressed prior to final publication. It was originally intended for this process to be completed at this meeting, but with the heavy focus on C++17, it slipped to the next meeting.

LEWG spent a significant amount of time reviewing the Graphics TS, which will provide 2D graphics primitives to C++ programmers. The proposal is progressing towards being sent onwards to LWG, but isn’t quite there yet.

Not much progress has been made on the Ranges TS and the Networking TS, again due to the focus on C++17. LEWG did review a proposal for minor design changes to the Ranges TS, and approved some of them.

Study Groups

Due to the meeting’s emphasis on C++17, most study groups did not meet, but I’ll talk about the few that did.

SG 1 (Concurrency)

SG 1 spent some time reviewing concurrency-related proposals slated for C++17, such as the handling of exceptions in parallel algorithms, as well as advancing its post-C++17 work: the second revisions of the Concurrency and Parallelism Technical Specifications.

The Concurrency TS v2 is slated to contain, among other things, support for floating-point atomics, atomic_view, a synchronized value abstraction, and emplace() for promise and future.

The Parallelism TS v2 is expected to contain a low-level library vector facility (datapar), as well as more forward-looking things (see proposals tagged “Concurrency” here).

SG 7 (Reflection)

SG 7 met for an evening session to provide design feedback on an updated version of the proposal that was chosen as the preferred approach for static code introspection at the last meeting.

The discussion focused most heavily on a particular design choice made by the proposal: the ability to reflect typedefs as separate from their underlying types (so for example, the ability for the reflection facility to distinguish between a use of std::size_t and a use of unsigned long, even if the former is a typedef for the latter). The issue is that the language does not treat typedefs as semantic entities in their own right, and a reflection facility pretending that it does can result in a variety of inconsistencies.

A prominent example is the treatment of template instantiations: if size_t is a typedef for unsigned long, then vector<size_t> and vector<unsigned long> are the same instantiation. Consider an implementation which has already instantiated vector<unsigned long>, and now encounters vector<size_t>; it resolves the size_t, realizes that it already has the instantation being referred to, and uses that instantiation. In this process, the information that this particular use of the instantiation originated from a place where the type argument was spelt size_t, can be lost.

The conclusion that the group tended towards was that desired uses of typedef reflection fall into two categories:

  • Cases where you want typedefs to be preserved in a type name because e.g. you’re presenting it to the user. For these cases, the reflection facility can provide a method like get_sugared_name() which makes a best-effort attempt to return a readable type name that has typedefs preserved (but makes no guarantees). This would be similar to how type names are printed in compiler diagnostics.
  • Cases where you truly want the typedef to be a distinct semantic entity. For these cases, the language needs a proper “strong typedef” facility (many have been proposed over time, most recently this one), and reflection can expose that if and when such a facility is added.

It was established at previous meetings that the proposal should built upon a type-list library facility; the beginnings of one are now in the works (being developed outside of SG 7).

Most interestingly, the proposal author hinted at what a future extension of the proposal to cover the other aspect of static reflection, reification (also called interface synthesis) could potentially look like:


// Current facility: call "reflexpr" on an entity to introspect it, yielding a
// compile-time meta-object (i.e. a type) that encodes information about the entity:
typedef reflexpr(int) MetaInt;

// Future extension: call "reflexpr" again on a meta-object to reify it:
typedef reflexpr(MetaInt) ReifiedInt; // ReifiedInt = int

In the above example, we just reify an unmodified meta-object, getting back the same entity that was originally introspected, but you can imagine performing modifications to the meta-object (such as adding methods to a type), and reifying the result, producing a new entity that doesn’t exist elsewhere in the code.

A ship vehicle for Reflection has not been chosen yet, but the general expectation is that it will be a Technical Specification.

SG 14 (Game Development & Low-Latency Applications)

SG 14 aims to engage with the game development and low-latency application developemnt (including finance/trading) communities – communities which have historically eschewed aspects of standard C++, such as exception handling, due to their unique performance constraints – to try to bring them into the standard C++ fold.

The group is very active, meeting during C++ standards meetings (including an evening session at this meeting), as well as at other events such as GDC, CppCon, and Meeting C++; it also holds regular teleconferences between in-person meetings.

Lately, members of the embedded computing community have expressed interest in the group’s work as well, as they share many of the same goals.

One of the foremost problems the group has been tackling is making exception handling performant enough to be palatable to these developer communities, or coming up with an alternative error handling mechanism that is. This report is a good summary of the latest efforts in this area, listing no fewer than 11 possible proposal ideas.

One thought that keeps coming up, in SG 14 but also in other contexts (such as the variant issue), is that the reason almost any operation in C++ can throw is that C++ tries to treat memory allocation as a recoverable failure, throwing std::bad_alloc on memory exhaustion. However, this rarely ends up being useful; for example, due to the way OSes overcommit memory, often memory exhaustion results in a crash before the memory allocator would nominally run out of memory and throw bad_alloc. If memory exhaustion weren’t treated as a recoverable error, the remainder of exceptional situations could much more easily be contained to a small portion of interfaces.

I haven’t had a chance to follow the rest of SG 14’s work in detail; if you’re interested, I encourage you to look at this overall status report, and to follow the group’s mailing list.

Next Meeting

The next meeting of the Committee will be in Issaquah, Washington (an hour outside Seattle), the week of November 7th, 2016.

Conclusion

This meeting saw the feature-completion of C++17. While some big-ticket items like modules did not make the train, I think the feature set we ended up with is pretty respectable, and the new language version will improve C++ programmers’ lives in significant ways.

I’m also very excited about what’s in the pipeline for post-C++17: modules, coroutines, ranges, contracts, reflection, and more facilities for concurrency and parallelism, among other things. Stay tuned for further reports!

Other Trip Reports

Herb Sutter’s trip report makes a good read as well, as does Michael Wong’s (in particular, these slides are a great overview of the current status of C++ standardization).

Posted in c++, programming | Tagged , , | 5 Comments

Trip Report: C++ Standards Meeting in Jacksonville, February 2016

Summary / TL;DR

Project What’s in it? Status
C++17 Filesystem TS, Parallelism TS, Library Fundamentals TS I, if constexpr, and various other enhancements are in. Concepts, coroutines, and unified call syntax are out. Default comparisons and operator. to be decided at next meeting. On track for 2017
Filesystems TS Standard filesystem interface Published! Merging into C++17
Library Fundamentals TS I optional, any, string_view and more Published! Merging into C++17
Library Fundamentals TS II source code information capture and various utilities Resolution of comments from national standards bodies in progress
Concepts (“Lite”) TS Constrained templates Published! NOT merging into C++17
Parallelism TS I Parallel versions of STL algorithms Published! Merging into C++17
Parallelism TS II TBD. Exploring task blocks, progress guarantees, SIMD. Under active development
Transactional Memory TS Transaction support Published! NOT merging into C++17
Concurrency TS I future::then(), latches and barriers, atomic smart pointers Published! NOT merging into C++17
Concurrency TS II TBD. Exploring executors, synchronic types, atomic views, concurrent data structures Under active development
Networking TS Sockets library based on Boost.ASIO Wording review of the spec in progress
Ranges TS Range-based algorithms and views Wording review of the spec in progress
Numerics TS Various numerical facilities Under active development
Array Extensions TS Stack arrays whose size is not known at compile time Withdrawn; any future proposals will target a different vehicle
Modules TS A component system to supersede the textual header file inclusion model Initial TS wording reflects Microsoft’s design; changes proposed by Clang implementers expected. Not targeting C++17..
Graphics TS 2D drawing API Wording review of the spec in progress
Coroutines TS Resumable functions Initial TS wording will reflect Microsoft’s await design; changes proposed by others expected. Not targeting C++17.
Reflection Code introspection and (later) reification mechanisms Design direction for introspection chosen; likely to target a future TS
Contracts Preconditions, postconditions, etc. Unified proposal reviewed favourably. Not targeting C++17.

Introduction

Last week I attended a meeting of the ISO C++ Standards Committee in Jacksonville, Florida. This was the first committee meeting in 2016; you can find my reports on the 2015 meetings here (May 2015, Lenexa) and here (October 2015, Kona). These reports, particularly the Kona one, provide useful context for this post.

This meeting was pointedly focused on C++17. With the window for getting new features into C++17 rapidly closing, it was (and continues to be) crunch time for all the committee subgroups. Many important decisions about what will make C++17 and what won’t were made this week, as I’ll relate below.

Work continued on Technical Specifications (TS’s) as well. As a reminder, TS’s are a mechanism to publish specifications for features that are not quite ready for full standardization; they give implementers and users a chance to try out features while leaving the door open for breaking changes if necessary. Progress was made on both TS’s already in flight (like Networking and Ranges), and new TS’s started for features that didn’t make C++17 (like Coroutines and Modules).

C++17

Recall that, since C++11, the committee has been operating under a release train model, where a new revision of the C++ International Standard (IS) ships every 3 years. For any given revision, whatever features are ready when “the train leaves” are in, and whatever is not ready is out.

For C++17, the train is in the process of leaving. According to the intended schedule, the end of this meeting was the deadline for completing design review for new features, and the end of the next meeting (this June, in Oulu, Finland) will be the deadline for completing wording-level review for the same. This means that, coming out of this meeting, C++17 is essentially feature-complete (although reality is bit more nuanced than that, so read on).

The set of candidate features vying to make C++17 was very large – too large to complete them all and still ship C++17 on time. As a result, hard decisions had to be made about what is ready and what is not. I will describe these decisions and the deliberations that went into them below. My personal opinion is that, while C++17 may not contain everything everyone hoped it might, it will still be an important language revision with a respectable feature set.

So, let’s see what will be in C++17:

Features already in C++17 coming into the meeting

I’ve listed these in my Kona report – see the list of features in C++17 coming into Kona, and the listed of features voted into C++17 at Kona; I won’t repeat them here.

Features voted into C++17 at this meeting

Technical Specifications that have been merged into C++17 at this meeting:

  • The Parallelism TS has been merged into C++17, with the exception of one component, dynamic execution policies, which have been held back and will remain in the second revision of the Parallelism TS for now. There was mild implementer opposition over the lack of implementation experience as part of a portable standard library (as opposed to implementation experience in third-party, mostly non-portable libraries, of which there is plenty), but the vote to merge passed in spite of this. The algorithms defined by this TS will go into namespace std (in the TS they were in std::experimental::parallel), and overload with the existing standard algorithms.
  • Most components of the first Library Fundamentals TS have been merged into C++17. Invocation traits and two small components of polymorphic allocators have been held back, and will remain in the second Library Fundamentals TS for now. The components defined by this TS will go into namespace std (in the TS they were in std::experimental).
  • The Filesystem TS has been merged into C++17 (in its entirety). There was mild opposition to this, mostly by implementers who support systems with non-hierarchical filesystems (such as IBM’s mainframe operating system, z/OS) which do not fit the filesystem model defined by the TS very well, but the vote to merge passed nonetheless. The components defined by this TS will go into namespace std::filesystem (in the TS they were in std::experimental::filesystem).
  • This is actually not a TS but a separate International Standard, but it seemed appropriate to list this it here as well: the Mathematical Special Functions IS has been merged into C++17. This was originally proposed and voted down in Lenexa (two meetings ago), over concerns about implementation difficulty by implementers who did not have userbases particularly clamoring for this functionality; since Lenexa, these worries have been allayed, in part by assurances that the Boost implementation is of sufficiently high quality to serve as a basis for standard library implementations. The functions defined by this IS will go into namespace std (in the IS, since it was targeted at both C and C++, they were in the global namespace).

Other features that have been voted into C++17 at this meeting:

Features that will come up for a vote to go into C++17 in Oulu

As I mentioned above, the last chance to vote new features into C++17 will be at the next meeting, in Oulu. Here I list the features that are expected to come up for such a vote.

It’s important to note that, even after a feature receives design approval from the relevant working group (Evolution for language features, Library Evolution for library features), as all features listed here have, it doesn’t get into C++17 until it’s voted in at a plenary meeting, and sometimes that vote fails (this happened to some features at this meeting). So, while all these features are targeted at C++17, there are no guarantees.

The majority of these features passed design review, or re-review, at this meeting. For the language ones, I discuss them in more detail in the Evolution Working Group section below.

Of the language features listed above, default comparisons and operator dot are slightly controversial; we’ll have to see how they fare at the vote in Oulu.

What was proposed for C++17 but didn’t make it

Unified Call Syntax

Unified call syntax failed to gain consensus, due to concerns that it has the potential to make future code brittle. Specifically, it was pointed out that, since member functions are only considered for a call with non-member syntax if there are no non-member matches, calls with non-member syntax written to rely on this feature to resolve to member functions can break if a matching non-member function is added later, even if the added function is a worse match than the member function. The feature may come up for a vote again at the next meeting if new arguments addressing these concerns are made, but for now it is not going into C++17.

Concepts

The Concepts Technical Specification (also called “Concepts Lite” to reflect that, unlike C++0x concepts, it includes only interface checking, not both interface and definition checking) was published in October 2015.

A proposal to merge the Concepts TS into C++17 was brought forward at this meeting, but it proved fairy controversial and failed to gain consensus. I was going to summarize the reasons why, but then I discovered fellow meeting attendee Tom Honermann’s excellent summary; I can’t possibly put it better or in more detail than he did, so I’ll just refer you to his post.

I’ll share a personal view on this topic: given how important a feature Concepts is for C++, I think’s it’s critical that we get it right, and thus I think the caution displayed in not merging into C++17 is appropriate. I also don’t view Concepts not merging into C++17 as “not having Concepts yet” or “having to wait another N years for Concepts”. We have Concepts, in the form of the Concepts TS. That’s published, and implemented (and is on track to be supported by multiple implementations in the near future), and I don’t see much reason not to use it, including in large production codebases. Yes, it being in a TS means that it can change in backward-incompatible ways, but I don’t expect such changes to be made lightly; to the extent that such changes are made, I would expect them to fall into the following categories:

  • Changes to the concept definition syntax, to be more amenable to separate checking of template definitions. I expect the amount of breakage this causes to be small, because concept definitions are a fairly small amount of code compared to the amount of code that uses these concepts.
  • A possible removal of one or both of the very terse syntaxes for defining constrained functions – the one that omits the template parameter list altogether, and the one that replaces it with a “concept introduction”. I would argue that avoiding these syntaxes in a large codebase is good engineering practice to begin with.
Coroutines

Recapping the status of coroutines coming out of the last meeting:

  • The stackless coroutines proposal championed by Microsoft (a.k.a. the await proposal) already undergoing wording review, but with its ship vehicle (C++17 or a TS) uncertain.
  • Stackful coroutines usable as a library, with a standardization attempt in a relatively early stage.
  • Attempts to create a unified approach (this one and this one) that combines the advantages of stackless (performance) and stackful (no viral effects on a codebase), in an early design stage.

Since then, there have been two interesting developments:

  • A relatively diverse group of people submitted an opinion paper arguing that the await proposal should target a TS, because of a lack of sufficient implementation and deployment experience, and because the design space for alternative approaches (such as the unified approach being sought) is still fairly open.
  • A more fleshed-out proposal for such a unified approach was brought forward. This bore a lot of similarity to the previous “resumable expressions” proposal, but with the significant change that calls across translation unit (TU) boundaries no longer required virtual function calls (which was the strongest criticism of resumable expressions at previous meetings); rather, an annotation system is proposed that allows the compiler to know which functions will be called as part of a coroutine execution, and generate efficient code accordingly.

    To avoid these annotations being viral like await, a mechanism for inferring the annotations within a TU is proposed; this is then extended to handle cross-TU calls by having the compiler generate two versions of a function (one for coroutine execution, and one for normal execution), and having the linker hook up cross-TU calls among these (the Transactional Memory TS uses a similar mechanism to deal with transaction-safe and transaction-unsafe versions of functions).

    The “unified” aspect of this approach comes from the fact that a compiler can use a stackful implementation for part or all of a coroutine execution, without any change to the syntax. While this proposal is obviously still in an early design stage, I got the impression that this was the first time a “unified coroutines” proposal was sufficiently fleshed out to make the committee view it as a serious contender for being the C++ coroutines design.

In light of these developments, a discussion was held on whether the await proposal should target a TS or C++17. The outcome was that a TS had a much stronger consensus, and this was the direction chosen. I would imagine that the unified proposal will then be pursued as a set of changes to this TS, or as a separate proposal in the same TS (or in a different TS).

What wasn’t even proposed for C++17

Modules

In Kona, the committee decided that Modules would target a TS rather than C++17. I said in my Kona report that there’s a chance the committee might change its mind at this meeting, but that I thought it was unlikely. Indeed, the committee did not change its mind; a discussion of this proposal from the authors of the Clang modules implementation to make changes to the design being proposed by Microsoft, made it clear that, while significant convergence has occurred between the two implementations, there still remain gaps to be bridged, and targeting the feature for C++17 would be premature. As a result, Modules will continue to target a TS.

The Modules TS was officially created at this meeting, with its initial working draft consisting of Microsoft’s proposal. (The Clang implementers will formulate updated versions of their proposal as a set of changes to this draft.) The creation of an initial working draft is usually just a procedural detail, but in this case it may be significant, as the GCC and EDG implementers may view it as unblocking their own implementation efforts (as they now have some sort of spec to work with).

I summarize the technical discussion about Modules below.

Concurrency TS

Due to its relatively recent publication (and thus not yet having a lot of time to gain implementation and use experience), the Concurrency TS was not proposed for merging into C++17.

Some people expressed disappointment over this, because the TS contains the very popular future::then() extension.

Transactional Memory TS

For similar reasons, the Transactional Memory TS was not proposed for merging into C++17.

Contracts

Significant design progress has been made on contracts at this meeting. What started out as two very different competing proposals, had by the beginning of the meeting converged (#1, #2) to the point where the remaining differences were largely superficial. During the meeting, these remaining differences were bridged, resulting in a truly unified proposal (paper forthcoming). The proposal is very simple, leaving a lot of features as potential future extensions. However, it’s still too early in the process to realistically target C++17.

Reflection

Reflection was never targeted for C++17, I just mention it because of its popularity. The Reflection Study Group did make significant progress at this meeting, as I describe below.

Evolution Working Group

Having given an overview of the state of C++17, I will now give my usual “fly on the wall” account of the deliberations that went on in the Evolution Working Group (EWG), which reviews the design of proposed language features. I wish I could give a comparably detailed summary of goings-on in the other subgroups but, well, I can only be in one place at a time🙂

EWG categorizes incoming proposals into three rough categories:

  • Approved. The proposal is approved without design changes. They are sent on to the Core Working Group (CWG), which revises them at the wording level, and then puts them in front of the committee at large to be voted into whatever IS or TS they are targeting. These proposals are targeting C++17 unless otherwise indicated.
  • Further Work. The proposal’s direction is promising, but it is either not fleshed out well enough, or there are specific concerns with one or more design points. The author is encouraged to come back with a modified proposal that is more fleshed out and/or addresses the stated concerns. At this point, proposals in this category have effectively missed the C++17 train.
  • Rejected. The proposal is unlikely to be accepted even with design changes.

Accepted proposals:

  • Concepts was discussed at length. In addition to debating whether or not the Concepts TS should merge into C++17 (which I’ve touched on above), EWG approved a minor enhancement to the feature: the restriction that requires-expressions can only appear inside a concept definition was relaxed; they can now appear in any expression context.

    The implementation status of Concepts also came up: Clang’s implementation is in progress, and MSVC and EDG both have it on their shortlist of features to implement in the near future; moreover, they have both indicated that Concepts not making it into C++17 will not affect their implementation plans.

  • A revised version of the dynamic memory allocation for over-aligned data proposal was accepted. Some concerns about ABI compatibility were raised, but they were worked out.
  • A revised version of the lambda capture of *this by value proposal was accepted as well. This version only proposes *this as a new kind of thing that can appear in the capture list; that results in the lambda capturing the enclosing object by value, and this inside the lambda referring to the copied object. (The previous version also proposed * to mean a combination of = and *this, but people didn’t like that.) A couple of extension ideas were floated around: allowing moving *this into the lambda, and capturing an arbitrary object to become the this of the lambda; those are left for future exploration.
  • A few changes to the previously accepted proposal to relax initialization rules for enumerations were made. Most notably, the scope of the proposal was expanded to cover all enumerations, not just those with no enumerators, because people felt special-casing the latter would be confusing.
  • Finishing touches were put on the constexpr_if proposal. The proposal has undergone two syntax changes since the last meeting. The original proposed syntax was:
    constexpr_if (...) {
    ...
    } constexpr_else constexpr_if (...) {
    ...
    } constexpr_else {
    ...
    }

    The underscores were then dropped, yielding:
    constexpr if (...) {
    ...
    } constexpr else constexpr if (...) {
    ...
    } constexpr else {
    ...
    }

    Finally, the shorter
    if constexpr (...) {
    ...
    } else if constexpr (...) {
    ...
    } else {
    ...
    }

    was proposed, and this is what was settled on in the end. The proposal was also modified to allow the construct outside of templates; the semantics for such uses is that the branch not taken is fully type-checked, but entities referenced in it are not odr-used, and return statements contained in it do not contribute to return type deduction.
  • Default comparisons passed its final round of design review. The semantic model that EWG ended up settling on is quite simple: an implicitly generated comparison operator for a class behaves as if it had been declared as a friend of the class just before the closing brace of the class declaration. Among other things, this allows libraries to leave unspecified whether their classes use explicit or implicit comparison operators, because users cannot tell the difference. The generation of an implicit operator is triggered the first time the operator is used without an explicit operator being in scope; a subsequent explicit declaration makes the program ill-formed.

    A notable change since the last version of the proposal is that comparing a base object to a derived object is now ill-formed. To keep comparison consistent with copy construction and assignment, slicing during copy construction and assignment will also become ill-formed, unless the derived class doesn’t add any new non-static data members or non-empty bases. This is a breaking change, but the overwhelming majority of cases that would break are likely to be actual bugs, so EWG felt this was acceptable.

    The semantics of <= and >= also came up: should a <= b be implemented as a < b || a == b or as !(a > b)? EWG confirmed its previous consensus that it should be the former, but current standard library facilities such as std::tuple use the latter. EWG felt that the library should change to become consistent with the language, while recognizing that it’s not realistic for this to happen before STL2 (the upcoming non-backwards-compatible overhaul of the STL). There was also some disagreement about the behaviour of wrapper types like std::optional, which wrap exactly one underlying object; some felt strongly that for such type a <= b should be implemented as neither of the above choices, but as a.wrapped_object <= b.wrapped_object.

  • Specifying expression evaluation order was briefly revisited, to choose between two alternatives for the evaluation of operands in a function call expression: left-to-right sequencing, or indeterminate sequencing without any interleaving. Proponents of the second option argued that it was sufficient to fix practically all the real-life bugs that motivated the feature, and that the first option would allow people to design APIs that rely on the left-to-right sequencing of function call expressions, which is seen as undesirable; nonetheless, the first option prevailed.
  • A std::byte type was proposed for the standard library, representing a byte of data without being treated as a character or integer type (the way char flavours are). It’s defined as enum class byte : unsigned char {};. EWG was asked to weigh in on extending C++’s aliasing rules to allow accessing the object representation of any object via a byte*, the way that’s currently allowed via a char*; this extension was approved. An alternative suggestion of allowing this for any scoped enumeration with a character type as its underlying type (as opposing to singling out std::byte) was rejected.
  • Template parameter deduction for constructors passed its final round of design review as well. Following feedback from the previous meeting, the proposal allows deduction via both implicit deduction guides (the constructors of the primary template) and explicit deduction guides (formerly called canonical factory functions). The syntax for the latter is:
    template <typename Iter>
    vector(Iter b, Iter e) -> vector<ValueTypeOf<Iter>>

    placed outside of a class declaration. Injected-class-names retain their meaning (referring to the current instantiation) rather than triggering deduction. A new addition to the proposal is the treatment of partial parameter lists. If a template-id omits some arguments which have defaults, the defaults are used rather than deduction being triggered. However, auto can be used instead of omitting the argument to trigger deduction for that argument only.
    Example:
    std::vector<int> v{myAlloc}; // uses std::allocator<int> (oops)
    std::vector<int, auto> v{myAlloc}; // allocator type deduced from 'myAlloc'
  • Hexadecimal floating-point literals. This is an uncontroversial feature that has been supported by C since C99; it was approved without objection.
  • A shorthand for using multiple attributes in the same attribute namespace, that makes [[using ns: attr1, attr2, attr3]] a shorthand for [[ns::attr1, ns::attr2, ns::attr3]]. In an attribute specifier using this shorthand, all attribute names are looked up in the specified attribute namespace, without fallback to the global attribute namespace. If you want attributes from different namespaces on the same entity, you can either not use the shorthand, or use multiple specifiers as in [[using ns1: a, b, c]] [[using ns2: d, e]].
  • Encouraging compilers to ignore attributes they do not recognize (a variation of part of this proposal). This cannot be made a hard requirement, because an implementation can provide implementation-defined behaviour to an attribute, so an implementation bent on giving an error for attributes it doesn’t know about could claim to recognize all attributes, and provide the behaviour of “giving an error” for all except specific ones.
  • An is_contiguous_layout type trait, which returns true for types for which every bit in the object representation participates in the value representation. Such a trait can be used to implement a higher-level is_uniquely_represented trait, which is true if two objects of the type are equal if and only if their object representations are equal; this is in turn used for hashing. (The difference between the two traits is that is_uniquely_represented can be specialized by the author of a class type, since the author gets to determine whether two objects with the same value representation are considered equal.) is_contiguous_layout requires compiler support to implement, so it was brought in front of EWG, which approved it.
  • template <auto V>, where V is a non-type template parameter whose type is deduced. In Kona it was discovered that this clashes a bit with Concepts, because the natural extension template <ConceptName V> (which, given the relationship between auto and concept names in other contexts, ought to mean a non-type template parameter whose type is deduced but must satisfy ConceptName) already has a meaning in the Concepts TS (namely, a type parameter which must satisfy ConceptName). The proposal author discussed this with with the editor of the Concepts TS, and decided this isn’t an issue: template <ConceptName V> can retain its existing meaning in the Concepts TS, while “a non-type template parameter whose type is constrained by a concept” can be expressed a bit more verbosely as template <auto V> requires ConceptName<decltype(V)>. The feature is targeting C++17, time permitting.

Proposals for which further work is encouraged:

  • An updated version of for loop exit strategies, which uses catch break and catch default to introduce the blocks that run after an early exit and after a normal exit, respectively. EWG liked the direction, but didn’t like the use of the catch keyword, which is strongly associated with exceptions. More generally, there was a reluctance to reuse existing keywords (thus disqualifying the alternative of case break and case default). Other ideas such as context-sensitive keywords (allowing on break and on default, with on being a context-sensitive keyword), and ugly keywords (like on_break and on_default) were proposed, but neither gained consensus. The proposal author said he would think offline about a better spelling.
  • Structured bindings were discussed extensively. The proposed syntax is auto {x, y, z} = expr;, which declares new names x, y, and z, which bind to the “components” of the object expr evaluates to. The notion of “components” is defined for three categories of types:
    1. Array types, for which the components are the array elements.
    2. Class types that support get<N>(o) which returns the Nth component of o, for which the components are whatever these get calls return. Notable examples are std::pair and std::tuple.
    3. Class types where all non-static data members are public, for which the components are the data members. If the type also supports get<>(), that takes precedence.


    Several notable points came up during this discussion:

    • The exact semantics of the feature, with respect to types and object lifetimes, needs to be nailed down. Initially, even the authors of the proposal were confused, but ultimately settled on the following proposed semantics:
      • An unnamed object of the aggregate type is created, as if by auto __o = expr;. Mandatory copy elision ensures that no actual copying is done. Alternatively, the user can use a reference syntax, such as auto& {x, y, z} = expr;, resulting in the unnamed variable correspondingly having reference type, as in auto& __o = expr;.
      • Where possible, x, y, and z are not variables, they are just aliases to components of the unnamed object. The mental model here is to imagine that the compiler re-writes uses of x to be uses of __o.field1 instead. (The alternative would be to make x, y, and z references to the components of the unnamed object, but this wouldn’t support bit-field components, because you can’t have a reference to a bit-field.) I say “where possible”, because this can only be reasonably done for aggregates in categories (1) and (3) above.
      • For aggregates in category (2) above, x, y, and z are variables whose type is deduced as if declared with decltype(auto). (They can’t be aliases in this case, because there’s no knowing what get<>() returns; for example, it could return an object constructed on the fly, so there would be nothing persistent to alias.)
    • The design of the customization point for case (2) needs to be nailed down. There was general agreement that it should be an error to list fewer variables than the aggregate has components; to enforce this for aggregates in category (2), the number of components they have needs to be discoverable, so in addition to get<>() they need to support something like tuple_size<Type>::value. Some people also felt that using re-using get<>() as the customization point is a mistake, and a new function meant specifically for use with this feature should be introduced instead.
    • An alternative syntax of auto [x, y, z] = expr; was proposed by some who argued that it looks more natural, because in a declaration context, having comma-separated things inside braces is unexpected.
    • Some people expressed a strong desire to support explicit types for the components, as in auto { X x, Y y, Z z } = expr;, where X, Y, and Z are type names (or, with the Concepts TS, concept names). This desire sort of clashes with the semantics of having x, y, and z be aliases to the components, because we don’t have the freedom to give them types other than the types of the components. (One can imagine a different semantics, where x, y, and z are copies of the components, where with explicit types we can ask for a components to be converted to some other type; the current semantics do not admit this sort of conversion.) However, it might still make sense to support explicit types and require that they match the types of the components exactly.

    The proposal authors intend to iterate on the proposal, taking the above feedback into account. It’s unlikely to make C++17.

  • A 16-bit floating point type, spelt short float. EWG liked the direction. Some details remain to be worked out, such as the promotion rules (the proposal had short float promote to float, but it was pointed out that because of varags, they need to promote to double instead), and accompanying standard library additions.
  • A class representing a status and an optional value, meant to be used in interfaces where an operation can fail (to handle disappointment, as the author puts it). The class is similar to std::optional, except that it also allows storing a separate status object, whether or not a value object is present. This is useful for environments where exceptions cannot be used, or where immediately throwing an exception is undesirable for some other reason (for example, if we want an exception to be thrown in a delayed fashion, after a return value has made it to another thread or something and we actually try to access it). This was brought in front of EWG, because it’s an attempt to shape the future of error handling in C++. EWG liked the approach, and provided two specific pieces of guidance: first, the class should be marked [[nodiscard]], to indicate that it should not be ignored when used as a return value; and second, that the copyability/movability of the type should reflect that of the underlying value type.
  • A new prefix, 0o, for octal literals. The existing prefix of just 0 makes it too easy to accidentally write an octal literal when you meant a decimal literal. The proposal author would like to eventually deprecate using just 0 as a prefix, though people pointed out this will be difficult due to the heavy use of octal literals in POSIX APIs (for example, for file permission modes).
  • Forward declarations of nested classes. This would allow things like X::A* to appear in a header without requiring a definition for X to also appear in the header (forward-declarations of X and X::A will be sufficient). EWG found the use case compelling, because currently a lot of class definitions to appear in headers only because interfaces defined in the header use pointers or references to nested classes of the type. Several details still need to be worked out. (For example, what happens if a definition of X does not appear in any other translation unit (TU)? What happens if a definition of X appears in another TU, but does not define a nested class A? What happens if it does define a nested class A, but it’s private? The answer to some or all of these may have to be “ill-formed, no diagnostic required”, because diagnosing errors of this sort would require significant linker support.)


Rejected proposals:

  • A proposed change to aggregate initialization rules was rejected. The proposal concerned a scenario where an explicit constructor has one parameter with a default argument. Such a constructor serves as both a converting constructor and a default constructor, and the explicit applies to both, disqualifying the class from certain uses that require a non-explicit default constructor. EWG felt that this is appropriate, and that if the class author intends for only the conversion constructor to be explicit, they can write a separate default constructor instead of using a default argument.
  • Using enumerators of an enum class without qualification in a switch statement was rejected, mostly because people felt that complicating C++’s name lookup rules in this way was not worth the win.
  • Disallowing comma elision in variadic function declarations failed to achieve consensus. The motivation for this proposal was to allow an eventual extension to variadic templates where void foo(int...); would declare a template with a variadic number of int parameters. The problem is, right now void foo(int...) is accepted as an alternative spelling for void foo(int, ...) which is a C-style varags function. This proposal would have disallowed the first spelling, leaving that syntax open for eventually denoting a variadic template. Notably, C already disallows the first spelling, which means this proposal would have improved compatibility with C; it also means any breakage would be limited to C++-only code using C-style varargs functions. Nonetheless, EWG members expressed concerns about code breakage, and the proposal didn’t gain consensus. It’s possible this may be revisited if the author comes back with data about the amount of real-world code breakage (or lack thereof) this would cause.
  • A small change to overload resolution rules, to say that a null pointer constant of integral type (i.e. 0 or NULL) should prefer to convert to std::nullptr_t over void*, failed to achieve consensus. The motivation was to support a proposed library change. Some people didn’t find this compelling enough, and felt we shouldn’t be catering to legacy uses of 0 and NULL as null pointer constants.
  • Not a rejection per se, but EWG decided to withdraw the Array Extensions TS. The design direction didn’t change since change since the Lenexa meeting: rather than dumb “arrays of runtime bound” and a smarter dynarray class to wrap them, we want language syntax for what is really a smarter class type. Withdrawing the TS is just a procedural move that implies that any future proposals will target a different ship vehicle (a new TS, or the IS).
  • Up-to expressions. These would have been expressions of the form [a..b), which would denote a range of values from a up to (but not including) b. The natural use case is integer ranges, although the syntax would have worked with any type that supported operator++. The [a..b) notation was inspired by the mathematical notation for half-open ranges, but implementers were strongly against this use of unbalanced brackets, pointing out that even if they didn’t make the grammar ambiguous strictly speaking, they would break tools’ ability to rely on bracket balancing for heuristics and performance. Alternative syntaxes were brought up, such as a..<b, but overall EWG felt that inventing a syntax for this is unnecessary, when a simple library interface (like range(a, b)) would do. The proposal author was encouraged to work with Eric Niebler, editor of the Ranges TS, to collaborate on such a library facility.
  • Iterating over multiple ranges simultaneously in a range-based for loop. The proposed syntax was for (auto val1 : range1; auto val2 : range2) { ... }. Rejected because structured bindings in combination with a library facility for “zipping” ranges into a single range of tuple-like objects will allow this to be accomplished with syntax like for (auto {val1, val2} : zip(range1, range2)). Concerns were raised about the ability of such a library facility to achieve the same performance as a first-class language feature could, but optimizer developers in the room said that this can be done.
  • Deprecating non-standard attributes in the global attribute namespace (part of this proposal) was rejected, because it would make it more cumbersome to write code that uses an attribute standardized in a particular version of C++ (say C++17), that compiles as both that version of C++, and the previous version (say C++14).
  • Encouraging implementations to diagnose auto operator=(const A&) { ... }, that is, an assignment operator whose return type is deduced using the auto placeholder. Since the auto placeholder always deduced a by-value return type, this is usually a bug (since assigment operators generally return by reference). EWG didn’t feel this was a problem worth solving.

Modules

EWG spent most of an entire day discussing Modules. The developers of Clang’s modules implementation described their experience deploying this implementation across large parts of Google’s codebase, with impressive results (for example, an average 40% reduction of compile times as a result of modularizing the most heavily used 10% of libraries). They then presented the most salient differences between their Modules design and Microsoft’s, formulated as a set of proposed changes to Microsoft’s design.

EWG discussed these proposed changes in depth. The following changes were reviewed favourably:

  • Requiring a module declaration to appear at the top of a file (modulo whitespace and comments). In Microsoft’s proposal, it can be anywhere, and declarations above it are considered to live in the global module. To accomodate declaring things in the global module, the syntax module { /* declarations here live in the global module */ } is proposed. The main motivations are to allow tools to associate files with modules more easily (by not having to parse too far from the beginning of the file), and to avoid imposing a requirement that declarations in the global module must appear before everything else.
  • Allowing the interface of a module to be split across several files. There will still be one primary module interface file, but parts of the module interface can live in secondary files called module partitions. The motivation here is to allow classes with circular dependency between their interfaces to live in two separate files that are partitions of the same module. They are still required to live in the same module; a previous version of Clang’s implementation allowed them to live in different modules, but this necessitated allowing one module to forward-declare entities owned by another module, which placed unfortunate constraints on how modules can be implemented. As a result, they are now required to be in the same module, but requiring them to be in the same file is too restrictive, hence the proposal to split a module interface across files. Importantly, module partitions can be compiled independently. Module partitions bear some resemblance to submodules (of which there is no formal notion in either design), but with the important difference that a module partition cannot be imported by a different module by itself; importing works at the level of entire modules.
  • Using a new syntax, such as module implementation ModuleName;, to begin a module implementation unit (while module interface units use module ModuleName;). The compiler already needs to know whether a translation unit is a module interface unit or a module implementation unit. It currently gets this information from metadata, such as compiler flags or the filename extension. This proposal places that information into the file contents.

The following changes did not yet gain a clear consensus in terms of direction. They will need to be iterated on and discussed further at future meetings:

  • Allowing modules to be found based on their names. This would change the module import syntax from import ModuleName; to import <ModuleName> (or import "ModuleName" or import <path/to/ModuleName>, or any other variation permitted by the #include syntax), with the intention being that it would allow the compiler to find the module based only on its name (together with some per-translation implementation-defined metadata, such as the “#include search path” or an analogue), rather than requiring a separate mapping from module names to their locations. EWG found the motivation to be reasonable, but expressed caution about using strings in this context, and suggested instead using a hierarchical notation that can correspond to a filesystem path rather than being one, such as import x.y.z; standing for the relative path x/y/z (much as with Java imports).
  • Probably the most controversial of the bunch: allowing macros to be exported by a module (and imported by another). Microsoft’s approach is to disallow this, instead requiring authors of a module who wish to export macros to define them in a side header instead, and have client code both import the module and #include the side header. The Clang implementers argued that this was too heavy a burden for module authors and users, particularly in cases where a macro is added to a component’s interface, necessitating a change in how the component is imported. After a lengthy discussion, a basic consensus emerged that there was a lot of demand for both (1) a way to import a module that imported any macros exported by it, and (2) a way to import a module that did not import any macros, and that a Modules proposal would need to support both. The possibility of standardizing these as separate TS’s was brought up, but discarded because it would be confusing for users. No consensus was reached on which of (1) or (2) would be the default (that is, which would simply writing import ModuleName; do), nor on what semantics (2) might have if the module does in fact export macros (the options were to given an error at the import site, and to import the module anyways, silently stripping macros from the set of imported entities).
  • A new mechanism for importing a legacy (non-modularized) header from a module (invoked by some new syntax, like import header "header.h";), which would cause the module to export all macros defined at the end of the header. The motivation for this is that, when transitioning a large codebase to use modules in some order other than strictly bottom-up, a contents of a legacy header can be brought in both through a direct #include, and via a module. Direct inclusion relies, as ever, on an include guard to determine whether the file has been previously included. An inclusion via a module must, therefore, cause that include guard to become defined, to avoid a subsequent direct inclusion bringing in a second copy of the declared entities. The Clang implementers originally tried having this mechanism export just the header guard, but that requires heuristically detecting which macro is the header guard; this can be done in most cases, but is practically impossible for certain headers, such as standard C library headers, which have more complicated inclusion semantics than simple include guards. Another alternative that was tried was allowing multiple inclusion, and performing equivalence merging (a deep structural comparison of two entities) to weed out duplicate definitions, but this was found to be slow (undoing much of the compile-time performance benefit that Modules bring) and error-prone (slight differences in inclusion contexts could lead to two instances of a definition being just different enough not to be merged).

Proposals Not Discussed

EWG has a pretty good track record of getting through most if not all of the proposals on its plate in a given meeting, but at this meeting, due to the amount of time spent discussing Concepts, Coroutines, and Modules, there were 17 papers it did not get a chance to look at. I won’t list them all (see the list of papers on the committee’s website if you’re interested), but I’ll call out three that I was particularly excited about and would have liked to see presented:

  • Default tuple-like access. This would have allowed the mechanisms used to access tuples, get<N>(t), tuple_size<T>::value, and tuple_element<N>::type, to be used on structures whose data members are all public (roughly; the exact conditions are spelled out in the paper). I was particularly excited about this, because it would have unlocked a simple form of reflection (iteration over members) for such structures. However, the proposal probably would have encountered opposition for the same reason (duplicating functionality that will arrive as part of a complete reflection proposal).
  • Overload sets as function arguments. This would have allowed passing the name of a set of overloaded functions as an argument to a function. This is accomplished behind the scenes by wrapping the name in a generic lambda, such as [](auto&&... args) { return f(args...); }. We can do this wrapping today explicitly in C++14 code, but the proposal would have hid it behind a short and intuitive syntax.
  • Return type deduction and SFINAE. This proposal addresses a notable shortcoming of C++14 return type deduction. Return type deduction allows us to write auto foo(args) { return expr; } instead of auto foo(args) -> decltype(expr) { return expr; }. This is great in that avoids repetition, but the second form has a crucial characteristic that the first form lacks: expr is subject to SFINAE in the second form (because it appears in the declaration). The proposal mitigates this shortcoming by extending SFINAE to the function body of a function that uses return type deduction in cases where the invocation happens in an unevaluated context. This approach addresses many use cases without requiring the function body to be mangled into the function name. Extending SFINAE tends to be a hard sell (for example, the C++11 extension of SFINAE to arbitrary expressions had significant opposition), but perhaps this proposal strikes a good balance and will have the potential to achieve consensus.

Library / Library Evolution Working Groups

Having spent practically all of my time in EWG, I didn’t have much of a chance to follow developments on the library side of things, but I’ll summarize what I’ve gathered during the plenary sessions.

I listed library features voted into C++17 at this meeting, and those expected to be voted at the next meeting.

I also mentioned that the first revision of the Library Fundamentals TS and the Filesystem TS have been merged into C++17.

The second revision of the Library Fundamentals TS has been sent out for balloting by national standards bodies at the last meeting. The library groups are now in the process of addressing comments from those ballots. A publication vote is expected in Oulu.

There will be a third revision (and beyond) of the Library Fundamentals TS, but it doesn’t have a formal working draft yet.

std::variant was originally targeted for the third revision of the Library Fundamentals TS, but thanks to its popularity and the degree of confidence in its design, it will now be proposed for C++17!

With the focus being on C++17, LWG did not get a chance to progress the Ranges TS or the Networking TS to a state where they’re ready to be sent out for balloting. Hopefully this will happen in Oulu.

Study Groups

SG 1 (Concurrency)

The first revision of the Parallelism TS has been merged into C++17.

The first revision of the Concurrency TS has been published. It will not merge into C++17.

The second revision of the Parallelism TS is under active development. Targeted features include task blocks, vector/SIMD support (several different proposals), a library for parallel for loops, and execution policies.

The second revision of the Concurrency TS is under active development. Targeted feature include executors (several proposals), synchronic types, atomic views, concurrent queues, distributed counters, and atomic floats.

The planned timeframe for these revisions is feature-complete by the end of 2016, published by the end of 2017.

There was an evening session on the topic of massive parallelism, that featured presentations by HPX and Khronos. Interest was expressed in standardized support for such things, but it was also pointed out that C++ first needs to improve its support for exploiting parallelism in ubiquitous devices (such as phones) before pursuing more specialized form factors.

SG 5 (Transactional Memory)

The Transactional Memory TS was not proposed for merging into C++17.

SG 5 did not meet this week, but plans to meet in the future to discuss proposals that may target a second revision of the TS.

SG 6 (Numerics)

SG 6 met for most of one day, and continued to review candidate proposals for the upcoming Numerics TS. The TS does not have a working draft yet, but an outline of its expected contents, with links to papers proposing components, can be found here.

SG 7 (Reflection)

SG 7 met for two evening sessions, and made very significant progress this week.

Out of the three approaches to static reflection (specifically, introspection) on the table – type property queries, static reflection, and static reflection via template pack expansion – the group arrived at clear guidance to pursue the second (static reflection), and gave the author of that proposal specific guidance on how to progress it.

Several considerations went into the choice of direction. First, it had become clear that we will, if not now then eventually, want to reflect entities that cannot be passed as template parameters, so it made sense to pick a proposal that used an operator syntax (reflexpr(name) in the chosen proposal) rather than a trait syntax. Of the two proposals that used an operator syntax, “static reflection” was preferred because it seemed more flexible, including extensibility to interface synthesis, which the reflection group expects to want to do in the future.

Specific guidance for the author of the “static reflection” proposal included avoiding situations where reflecting over an entity at different points in a program yields different results (due to e.g. additional declarations of the entity having been made, which provide extra information, like an extra default argument), and steering clear of syntax-level reflection (that is, allowing reflection to observe how something was written in code rather than just what the properties of a semantic entity are). The most prominent example of the latter is reflection just telling you the type of a member, versus telling you the specific typedef used to write down that type. While good use cases for the latter have been brought forth, the group views this feature as dangerous territory, and suggests leaving it for a subsequent iteration of the proposal.

SG 7 intends to look at at least one more updated version of the “static reflection” proposal before forwarding it to EWG.

The group also expects to need help from LEWG for library facilities in support of reflection: compile-time strings, which are being worked on, and type lists.

After forwarding an introspection proposal to EWG, SG 7 intends to look at proposals for interface synthesis – the second half of static reflection, where, rather than introspecting entities to get some metadata about them, you take some metadata (that you perhaps have massaged), and reify it into new entities in your program. There is already one such proposal in the queue.

SG 10 (Feature Test)

SG 10 is keeping SD-6, the committee’s standing document listing recommended feature testing macros for various language and library features, up to date. The latest draft be found here.

SG 12 (Undefined Behaviour)

SG 12 hoped to meet this week, but was unable to, due to its chair being tied up in other groups. It hopes to meet instead in Oulu.

SG 13 (Human-Machine Interaction)

The 2D drawing API proposal, expected to ship as a TS, now has standard wording, review of which is in progress.

SG 13 also reviewed a proposal for a standard interface for input event handling; the review was brief because the author was not present in person. A possible interaction with the Networking TS was brought up, as that also has a notion of event queues.

The study group, originally called Graphics and later I/O, has been renamed to Human-Machine Interaction.

SG 14 (Game Development & Low-Latency Applications)

SG 14 has a number of proposals in front of it (see proposals targeted to SG 14 in the list), and they have been holding regular teleconferences, as well as discussions on the group’s public mailing list, about them.

The group did not meet formally this week, but there were two evening sessions on topics it had interest it.

The first was the session on massive parallelism which I described in the SG 1 section above.

The second was a session on a proposal for a packaging system for C++, which I talk about below.

A Packaging System for C++

Addressing questions of code distribution was explicitly made a non-goal of Modules, to limit scope creep, but it was imagined that other proposals that address such questions would follow. This is such a proposal, except that this proposal endeavours to support both Modular and non-Modular code.

The proposal consists of two parts: a specification for a packaging system itself, which is clearly out of scope for the Standard (but may be in scope for something else produced by the committee, such as a Standing Document); and some language syntax (#using PackageName) to interface with the packaging system, which would need to be standardized.

Three main pieces of feedback were given in the discussion about this proposal. First, that we need to figure out what portion of such a system it is reasonable to standardize in a document published by the committee (whether the Standard or a Standing Document), versus some other forum. Second, people were hesitant about giving compilers build system-like responsibilities the way this proposal does, and suggested instead a cleaner delineation between the roles of the two. Finally, the proposal focuses on source distribution because binary distribution is a tougher problem to solve due to ABI issues; people felt it was worth trying to address binary distribution nonetheless.

Next Meeting

The next meeting of the Committee will be in Oulu, Finland, the week of June 20th, 2016.

Conclusion

For the first time, we have a pretty good idea of what’s going to be in C++17. While it may not be everything everyone wanted, it’s still shaping up to be a pretty solid release of the language, and will be accompanied by important Technical Specifications that round it out, such as Concepts, Ranges, Modules, and Coroutines.

The level of participation in C++ standardization is the highest it’s been in recent memory (and possibly ever), and I’m excited about continue to observe, participate in, and report on it. There will be two more meetings this year – stay tuned for further reports!

Other Trip Reports

Herb Sutter’s trip report is a good read as well, giving more in-depth background on the standardization process and the role of Technical Specifications.

Posted in c++, programming | Tagged , , | 17 Comments

Featured Cover: To Zanarkand

Today, rather than featuring an original piece, I thought I’d give a shout-out to all the wonderful talent out there on YouTube, and feature a cover of a piece by a YouTube artist – or, in this case, two artists.

This is a piano duet, where Kyle Landry and Sherry Kim present their take on “To Zanarkand”, from the soundtrack of the popular RPG Final Fantasy X.

I’ve never played any of the Final Fantasy series of games, but I’ve been a fan of their soundtracks for a long time. I find this cover particularly compelling due to the interaction between the two pianists, which adds a dimension to the performance that you don’t see in a solo act.

“Zanarkand” is the name of a (ruined) city in the fictional world of Final Fantasy X.



For reference, here is (a magnificent live performance of) the original piece from the sountrack. Very much worth checking out in and of itself!



And, as a bonus, here’s a violin cover of the same piece by the incredibly talented Taylor Davis:



Hope you’ve enjoyed them!

Posted in featured song, music | Tagged | Leave a comment

Featured Song: Pain

I’m going to stray into the world of alternative rock again, with another song from Jimmy Eat World.

I’ve previously featured “Hear You Me” from their album Bleed American. Today’s selection is from their subsequent 2004 album, Futures.

Futures is a darker album than Bleed American, and that really shows through in today’s song, “Pain”, which is probably one of Jimmy Eat World’s angstiest works to date. Naturally, it is precisely this intensity that makes me like the song so much.



Lyrics and discussion can be found here.

I’m also going to give mention to a very memorable acoustic cover of this song that I came across on YouTube:



I find this cover very unique because, it addition to the cover artists obviously being quite talented, their interpretation of the song gives rise to a cover that has a very different sound and atmosphere from the original song, and yet is still very compelling. Kudos to them!

Posted in featured song, music | Tagged | Leave a comment

Featured Song: The Last Crusade

I introduced Epica into this series a few months ago, when I featured their song “Façade of Reality”.

I remarked at the time the similarity in sound between that song, and some of After Forever‘s preceding works, unsurprising due to both being the creation of composer Mark Jansen.

Despite an early similarity to After Forever, Epica has over time developed a distinctive sound of their own, which is at times more upbeat and adventurous. Today’s selection – “The Last Crusade” from Epica’s second full-length album, Consign to Oblivion – is a good demonstration of this. Still touching on religious themes, it’s a more fast-paced and cinematic song than “Façade of Reality”.

This song is also another example of Mark Jansen’s fondness for telling stories that span several songs; much as “Leaden Legacy” and “Façade of Reality” were part of a collection of songs spanning different albums (and, in this case, bands!) called “The Embrace That Smothers”, so “The Last Crusade” is the first part of a new collection of Epica songs, again spanning multiple albums, called “A New Age Dawns”.



It’s also worth checking out a live version of this song, performed by Epica in Miskolc, Hungary for their live album, The Classical Conspiracy. I really enjoy the descant that lead singer Simone Simons throws into the works at the end of the song.



Featured lyrics:

Don’t be afraid, participate and
Just give us all your trust
Your soul will be saved
Just follow me, I’ll set you free so
Get ready to join the
Very last crusade

Full lyrics can be found here.

Posted in featured song, music | Tagged | Leave a comment

Featured Song: Silhouette of a Dancer

I’ve featured two songs by Delain in this series so far; time for a third!

This one is from their debut album Lucidity again, called “Silhouette of a Dancer”.

I really like this song for its mix of symphonic and progressive elements; the second half of the piece, where it progresses through several different styles/atomspheres, is particularly nice.



Featured lyrics:

Waiting for a change
I can’t fight these chains everyday
I bleed to avoid the pain
Everyday I fade a little more

Full lyrics can be found here.

Delain also released a shorter, acoustic version of the song, on their single See Me In Shadow; it’s also quite beautiful:

Posted in featured song, music | Tagged | Leave a comment