Trip Report: C++ Standards Meeting in Kona, February 2017

Summary / TL;DR

Project What’s in it? Status
C++17 See below Draft International Standard published; on track for final publication by end of 2017
Filesystems TS Standard filesystem interface Part of C++17
Library Fundamentals TS v1 optional, any, string_view and more Part of C++17
Library Fundamentals TS v2 source code information capture and various utilities Published!
Concepts (“Lite”) TS Constrained templates Published! Not part of C++17
Parallelism TS v1 Parallel versions of STL algorithms Part of C++17
Parallelism TS v2 Task blocks, library vector types and algorithms 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 See below Under active development
Networking TS Sockets library based on Boost.ASIO Resolution of comments on Preliminary Draft in progress
Ranges TS Range-based algorithms and views Resolution of comments on Preliminary Draft in progress
Numerics TS Various numerical facilities Under active development
Modules TS A component system to supersede the textual header file inclusion model First version based largely on Microsoft’s design; hope to vote out Preliminary Draft at next meeting
Graphics TS 2D drawing API Under active design review
Coroutines TS Resumable functions, based on Microsoft’s await design Preliminary Draft voted out for balloting by national standards bodies
Reflection Code introspection and (later) reification mechanisms Introspection proposal passed core language design review; next stop is design review of the library components. Targeting a Reflection TS.
Contracts Preconditions, postconditions, and assertions Proposal passed core language design review; next stop is design review of the library components. Targeting C++20.

Introduction

A few weeks ago I attended a meeting of the ISO C++ Standards Committee (also known as WG21) in Kona, Hawaii. This was the first committee meeting in 2017; you can find my reports on 2016’s meetings here (February 2016, Jacksonville), here (June 2016, Oulu), and here (November 2016, Issaquah). These reports, particularly the Issaquah one, provide useful context for this post.

This meeting was focused on wrapping up C++17, iterating on the various in-progress Technical Specifications (TS), and picking up steam on C++20.

As I described in my previous report, at the end of the Oulu 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, and the comment period concluded prior to the Issaquah meeting, which was then heavily focused on addressing the resulting comments.

The aim for this meeting was to resolve the remaining comments, and – thanks to a lot of hard work, particularly from the Library groups which were swamped with a large number of comments to address – we were successful in doing so. At the end of the meeting, a revised draft of the C++17 standard, with the comments addressed – now labelled Draft International Standard (DIS) – was sent out for a second round of voting and comments.

As per ISO procedure, if the DIS vote is successful, the committee can proceed to final publication of C++17 (possibly with further modifications to address DIS comments) without a further round of voting and comments; this was the case for C++14, and it is hoped to be the case again for C++17.

C++17

Since at the CD stage, C++17 is supposed to be feature-complete, no new features were voted into C++17 at this meeting (see this for a list of features in C++17). The only things that were voted in were minor changes to resolve CD comments. I call out some of the notable ones below:

Changes voted into C++17 at this meeting

C++20

With C++17 being wrapped up with final comment resolutions, sights are increasingly set on the next release of the language’s International Standard (IS), C++20.

C++20 doesn’t have a working draft yet (it can’t per ISO procedure until C++17 is published), but a number of features targeted for it have already passed design review (see my previous posts for details), and many more are in the queue.

Notably, at this meeting, in addition to discussing individual proposals targeted for C++20, a plan for an overall direction / set of primary goals for C++20 was also discussed. The discussion was prompted by a paper in the pre-meeting mailing outlining such a proposed vision, which was discussed during an evening session on Thursday.

This paper suggests that we aim to get the following major features into C++20:

  • Concepts
  • Modules
  • Ranges
  • Networking

It does not suggest focusing on these features to the exclusion of others, but does propose prioritizing these over others. The reasoning for why these features merit special attention is well-argued in the paper; read it for details.

It’s worth noting that each of these features is first being standardized in the form of a Technical Specification, and these are at various stages of publication (Concepts is published; Ranges and Networking have had Preliminary Drafts published and comments on them are in the process of being addressed; for Modules, we hope to publish a Preliminary Draft at the next meeting). Getting these features into C++20 will require promptly completing the TS publication in cases where it’s not there yet, and then merging the TS’s into C++20.

The proposal for focusing on these four was received favourably by the committee. It is very important to note that this should not be construed as a promise to get these features into C++20; the committee isn’t in a position to make such a promise ahead of time, nor is anyone on it. As always, a feature only goes into the IS wen it’s ready – that is, when the committee has a high confidence in the design, its specification, its implementability, the interaction of the feature with other language and library features, and the appropriateness of the feature for standardization in the context of the language as a whole. We will work hard to get these features into C++20, but there are no promises.

Technical Specifications

The committee has a number of Technical Specifications in flight, and others in the planning stage. I’ll mention the status of each.

Recapping the procedure for publishing a Technical Specification:

  • 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
  • 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, the Coroutines TS was sent out for its PDTS ballot. The Modules TS came close, but didn’t quite make it.

Ranges TS

The Ranges TS was sent out for its PDTS ballot at the end of the last meeting. The ballot comments have since come back, and the library groups have been busy addressing them, resulting in a few changes to the working draft being approved. With the focus being on the C++17 CD comments, however, not all comments have been addressed yet, and the TS is not yet ready for final publication.

Networking TS

The Networking TS was also sent out for its PDTS ballot at the end of the last meeting and, as with the Ranges TS, the ballot comments have come back. The library groups did not have much time to spend on addressing the comments (due to the C++17 focus), so that work will continue at the next meeting.

Coroutines TS

The Coroutines TS – which contains the “stackless coroutines” / co_await proposal based on Microsoft’s design – was approved to be sent out for its PDTS ballot at this meeting. (This was attempted at the last meeting, but it was voted down on the basis that there had not been time for a sufficiently thorough review of the core language wording. Such review has since taken place, so it sailed through this time.)

As mentioned in my previous posts, there are also efforts underway to standardize a different, stackful flavour of coroutines (the latest iteration of that proposal suggests a library interface similar to the call/cc facility found in some functional languages), and a proposal to unify the two flavours (this latter seems to be stalled after a discussion of it at the last meeting convinced some people that unification is not worth it).

These alternative proposals are progressing (or not) independently of the Coroutines TS for the time being. Depending on how they progress, they may still have an impact on the form(s) in which coroutines are ultimately standardized in the C++ IS.

Concepts TS

The Concepts TS was published in late 2015, and is now being eyed for merger into C++20.

Recall that the purpose of standardizing a feature as a Technical Specification first, is to give implementers and users the ability to gain experience with the feature, and provide feedback that may motivate changes to the feature, before standardizing it in its final form.

Now that the Concepts TS has been published for a while, and a compiler that supports it (GCC 6) released almost a year ago, user and implementer feedback (the latter primarily from developers working on an implementation in Clang) has started trickling in.

(There was previously an attempt to merge the Concepts TS into C++17, which failed because at that point, the amount of user and implementer feedback had been small, and the committee felt people should have more time to try the feature out.)

The feedback so far has generated a few proposals for changes to the Concepts TS (P0342, P0464, and P0587). Some of these were looked at this week; I summarize the technical discussion below, but the high-level summary is that, while people agree on the general direction of some changes, other proposed changes remain rather controversial.

One thing that’s not controversial, is that everyone wants Concepts to make it into C++20. Procedurally, the question arose whether we should (1) merge the TS into the IS now, and treat remaining points of contention as “issues” to be tracked and resolved before the publication of C++20; or (2) resolve the issues in the Concepts TS working draft, and only then merge the result into C++20. A proposal to take route #1 (merge now) failed to gain consensus in the Evolution Working Group (EWG), so for now, the plan is to take approach #2 (resolve issues first, merge after).

Modules TS

Modules currently has two implementations – one in MSVC, and one in Clang – which diverge in some aspects of their conceptual and implementation models. Most notably, the Clang implementation includes macros in the set of entitites that can be exported by one module and imported by another, while the MSVC one does not.

At the October 2015 meeting (which, as it happens, was also in Kona), it was decided that, since supporting macros is both contentious and comes with significant implementation complexity, Modules will initially be pursued in the form of a Technical Specification that does not support macros, and macro support can be considered for a second iteration of the feature (which I’ll henceforth refer to as “Modules v2”; the ship vehicle for that is still to be determined – it might be a second Modules TS, or it might be C++20).

Accordingly, the current Modules TS working draft largely reflects Microsoft’s design.

Meanwhile, the Clang implementers have submitted a proposal for design changes that includes adding support for macros among other, smaller changes. EWG looked at parts of this proposal at the February 2016 meeting in Jacksonville, and some of the smaller changes gained the group’s consensus at that time.

However, it appears that there was some confusion as to whether those changes were intended for Modules v1, or v2. Since one of the proposals in the paper was adding macro support, a feature previously earmarked for v2, some people assumed the entire paper was v2 material. Other people had understood that the smaller changes that were approved, were approved for v1.

This misunderstanding came to light when the Modules TS (v1) working draft (which does not contain the mentioned changes) came up for a vote in full committee to be sent out for its PDTS ballot. The vote failed, and the matter referred back to EWG to clarify whether the changes in question are in fact approved for v1 or not.

EWG ended up effectively re-discussing the proposed changes (since during the first discussion, it wasn’t clear whether people were considering the changes for v1 or v2), with the outcome being that some but not all of them had consensus to go into v1 (I summarize the technical discussion below).

The hope is that Modules v1, as amended with these approved changes, can be sent out for its PDTS ballot at the next meeting (this July, in Toronto).

Parallelism TS v2

Not too much new to report for Parallelism TS v2. Task blocks are already in the working draft, while vector types and algorithms are still working their way through the library groups.

Concurrency TS v2

The Concurrency TS v2 does not have a working draft yet. New proposals being considered for it include an RAII interface for deferreed reclamation, hazard pointers, an RCU API, and padding bits for compare-and-excahnge. The concurrent queues proposal has been approved by SG1 (the Study Group that deals with concurrency) and forwarded to the library groups for review.

Executors, probably slated for a separate TS at this point, have a unified proposal, an updated version of which was discussed in SG1. One of the reasons executors are taking so long to standardize is that different communities want them for different use cases, and accommodating all of them adds significant complexity to any proposal. It is likely that the initial version to be standardized will be restricted to a smaller feature set.

Future Technical Specifications

Several future Technical Specifications are planned as well.

Reflection

The Reflection Study Group (SG 7) approved a proposal for static introspection (summary, design, specification) at the last meeting. This week, the Evolution Working Group looked at it and approved it as well; they also agreed with the decision to start by standardizing the proposal as a TS. The next stop for the proposal is the Library Evolution Working Group.

There were some proposals in the latest mailing that aimed to change aspects of the introspection proposal – not core aspects like “what can be reflected”, but more like “how does the reflection facility integrate into the language”, such as the proposal to reflect through values instead of types. These proposals will be given due consideration (and SG 7 started looking at them this meeting; I summarize the discussion below), but in the meantime, the introspection TS will go forward as-is, so that valuable implementer and user feedback can be collected on the core aspects of the proposal as soon as possible. Changes such as reflecting through values can then be made post-TS.

Numerics

As previously outlined, the Numerics Study Group (SG 6) plans to put out a Numerics TS containing various facilities (summarized here). SG 6 met for two days this week, primarily to work on the TS; the group’s chair hopes that an initial working draft for the TS, to be edited collaboratively over Github, will be ready for the next meeting.

SG 6 also approved some library features related to bitwise operations (P0237, P0553, P0556) that are not slated for the Numerics TS, but will go directly into C++20 (or the latest version of the Library Fundamentals TS, at LEWG’s choosing).

Graphics

The Graphics TS, which proposes to standardize a set of 2D graphics primitives inspired by cairo, has updated wording that addresses issues raised during a previous round of design review. The Library Evolution Working Group looked at the updated proposal this week, and suggested one more round of changes; the hope is to forward the proposal to the Library Working Group (which will then review it at the wording level) at the next meeting.

Evolution Working Group

I sat in the Evolution Working Group (EWG) for the duration of the meeting, so in addition to the general overview I gave above, I can go in more details about the technical discussion that took place in that group.

To recap, EWG spends its time evaluating and reviewing the design of proposed language features. This week, it briefly addressed some remaining C++17 issues, and then spent rest of the week on post-C++17 material (such as C++20, and Technical Specifications like the Modules TS).

C++17 Topics

  • National body comments on the C++17 CD remaining to be addressed. (Note that the comments can be found in two documents: official comments, and late comments)
    • constexpr static members of enclosing class type (US 24). EWG looked at this at the last meeting, and said this extension would be considered for C++17 if the details were worked out in a paper. As no such paper appeared at this meeting, the extension was now rejected for C++17. It could come back in a later standard.
    • When are get<>() functions called in decomposition declarations? (Late 3). The current wording says that they are called “eagerly”, at the point of decomposition. At the last meeting, EWG was in favour of changing that to “lazily”, that is, being called at the point of use of the decomposed bindings, but this change too required a paper. Again no such paper appeared, and moreover the comment author said that, upon contemplation, it seems like a tricky change to make, and probably not worth it, so the “lazy” idea was abandoned.
    • Should library implementers have the freedom to add constexpr to library functions where the standard doesn’t specify it? (GB 38). This was proposed for previous standards but rejected, mainly because of portability concerns (library functions that the standard didn’t specify to be constexpr still couldn’t be portably used in contexts that require constant expressions, such as array bounds). It was now requested again for C++17; however, the idea still didn’t have EWG’s consensus. There is some hope it may yet in C++20.
  • Terminology: “structured bindings” vs. “decomposition declarations”. The ability to decompose a tuple-like object into its constituent parts, as in auto [a, b, c] = foo(); , was called “structured bindings” during design discussions, but the wording in the standard refers to declarations of this form as “decomposition declarations”. To avoid confusion stemming from having two names for the same thing, “decomposition declarations” were renamed to “structured binding declarations”.
  • Class template argument deduction
    • There was some discussion of whether implicit deduction guides should be kept. The consensus was that most of the time they do the right thing (the exceptions typically being classes whose constructors involve a lot of metaprogramming, like std::tuple) and they should be kept.
    • Copying vs. wrapping behaviour. Suppose a is a variable of type tuple<int, int>, and we write tuple b{a};. Should the type of b be tuple<int, int> (the “copying” behaviour), or tuple<tuple<int, int>> (the “wrapping” behaviour)? This question arises for any wrapper-like type (such as pair, tuple, or optional) which has both a copy constructor and a constructor that takes an object of the type being wrapped. EWG felt copying was the best default. There was some talk of making the behaviour dependent on the syntax of the initialization (e.g. the { } syntax should always wrap) but EWG felt introducing new inconsistencies between the behaviours of different initialization syntaxes would do more harm than good.
    • Whether you should be able to define explicit deduction guides as deleted. EWG agreed that this is useful, but for practical reasons (being so late in the C++17 cycle), the relevant wording will be placed into a Defect Report applicable to C++17 rather than into the C++17 draft itself.
  • std::launder() is a library function with special behaviour that was added to C++17 to allow certain patterns of code (which arise, for example, in typical implementations of std::variant), to have well-defined behaviour without excessively constraining compiler optimizations such as devirtualization. At this meeting, a proposal to achieve the same goal via different means (no library function, just changes to core language wording) was put forward. However, during discussion it came to light that the proposed alternative would not handle all affected scenarios (particularly scenarios where vtable pointers are in play), and it did not gain consensus.

Post-C++17 Proposals

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

Accepted proposals:

  • Allowing attributes on template instantiations. C++ allows many entities in the program (such as variables, types, and functions) to be annotated with attributes, but explicit template instantiations are not one of them. Annotating explicit instantiations turns out to be useful, particular for visibility attributes, so this ability was added. Since this is more an oversight in the initial specification of attributes than a new feature, in addition to being in C++20, it will be published as a Defect Report potentially applying as far back as C++11.
  • Simplifying implicit lambda capture. This proposal simplifies the specified procedure for determining whether a variable referenced inside the body of a lambda with a capture-default, is captured by the lambda. The main motivation is that the current procedure trips up in some scenarios involving if constexpr. The user impact should be limited to allowing those previously-problematic cases. (In theory, the change could result in lambdas notionally capturing some variables that they don’t strictly need to and didn’t capture before, but optimizers should be pretty effective in optimizing such captures out.)
  • Consistent comparisons. EWG looked at various proposals for default comparisons at the last meeting, and the consensus that emerged was that (1) we want a three-way comparison operator; (2) two-way comparison operators should be “desugared” to the three-way comparison operator; (3) most classes should only need to define the three-way comparison operator, and the language could provide some help in doing that.

    This paper formalizes that consensus into a proposal. The three-way comparison operator is spelt <=> (the “spaceship operator”), and the compiler can generate a default implementation if one is declared as = default. In addition, the proposal supports the notion of different strengths of ordering by making the return type of the spaceship operator be one of std::strong_ordering, std::weak_ordering, or std::partial_ordering, which are enumeration-like types (though not actual enumerations) with appropriate conversions between them; it also supports the notion of types that can be compared for equality but are not ordered, for which the spaceship operator would return std::strong_equality or std::weak_equality.

    EWG passed the above parts of the paper; they will now go to LEWG for library review, and CWG for core language wording review. The paper also contained an optional extension, where some user-defined types would get the spaceship operator auto-generated for them without even a defaulted declaration (similar to the previous default comparison proposal that almost made it into C++17). This extension did not gain EWG’s consensus at this time, although it may come back in revised form.

    (The paper also contained an extension to support chaining comparisons, that is, to let things like a == b == c have the meaning of (a == b) && (b == c) that was likely intended. This also didn’t gain consensus, though it could also come back after some compatibility analysis is performed to determine how much existing code it would break.)
  • Static reflection. This is the proposal that the Reflection Study Group approved at the last meeting. EWG approved this without asking for any design changes; it concurred with the Study Group’s opinion that the ship vehicle should be a Reflection TS (as opposed to, say, C++20), and that standardization of the proposal as written should proceed in parallel with alternative syntaxes being contemplated. The next stop for this proposal is the Library Evolution Working Group; bikeshedding of the reflection operator’s spelling (the latest draft of the paper contains $reflect, while previous ones contained reflexpr) will take place there.
  • Implicit moving from rvalue references in return statements. This proposal argues that in a function return statement, you practically always want to move from an rvalue reference rather than copying from it, and therefore the language should just implicitly move for you instead of requiring you to write std::move. Code that would break as a result of this change is almost certainly wrong to begin with.
  • Contracts. This is a refinement of the proposal for contract checking that was approved at previous meeting.

    There was one point of controversy, concerning the use of an attribute-like syntax. Some people found this objectionable on the basis that attributes are not supposed to have semantic effects. Others pointed out that, in a correct program, the contract attributes do not, in fact, have a semantic effect. Of particular concern was the “always” checking level specified in the proposal, which allows marking specific contract checks as being always performed, even if the program-wide contract checking level is set of “off“; it was argued that this means a conforming implementation cannot ignore contract attributes the way it can ignore other attributes.

    To resolve this concern, options such as using a different (non-attribute) syntax, or removing the “always” checking level, were considered. However, neither of these had stronger consensus than the proposal as written, so the proposal was sent onwards to the Library Evolution Working Group without changes.
  • short float. This is what it sounds like: a shorter floating-point type, expected to be 16 bits long on most platforms, to complement the typically 32-bit float and 64-bit double.

Proposals for which further work is encouraged:

  • Proposed changes to the Concepts TS. I talk about this below.
  • Abbreviated lambdas for fun and profit. This is really five separable proposals to abbreviate the syntax of lambdas further. All but the first one were rejected.
    • A terser syntax for single-expression lambdas (that is, lambdas whose body consists of a single return statement). This has been desired for a long time; the general idea is to eliminate the braces and the return keyword in this case. The problem is that just putting the expression after the lambda-introducer and optional parameter list leads to ambiguities. This paper proposes writing => expr; EWG encouraged thinking about more options.
    • Allow introducing parameters without a type specifier (that is, not even auto or auto&&). The problem with the naive approach here is that it’s ambiguous with the case where a parameter has a type specifier but no name. The paper proposes several possible solutions; EWG found them inelegant, and more generally felt that this problem space has already been explored without much fruit.
    • A way to request that SFINAE apply to a lambda’s deduced return type. The motivation for this is similar to that of a similar proposal along these lines. This idea had some support, but not consensus.
    • A way to request a deduced noexcept-specification. As with the earlier noexcept(auto) proposal, EWG did not find this sufficiently motivated.
    • A way to request that arguments to the lambda be automatically forwarded (in the std::forward<Type>(value) sense) in the body expression. EWG agreed that having to litter generic code with calls to std::forward is unfortunate, but felt that a solution to this problem should not be specific to lambdas.
  • std::call_cc() stackful context switching. This is an updated version of the earlier stackful coroutines proposal, with the library interface changed from std::execution_context (whose name clashed with a different type of “execution contexts” in the unified executors proposal) to std::continuation and std::call_cc(), names that some might recognize from Scheme and other functional languages. EWG looked at this in joint session with the Concurrency Study Group. The main purpose of the discussion was to determine whether the proposed interface is at the right level of abstraction for standardization. There wasn’t much consensus on this topic, with some liking the interface as written, others arguing for a lower-level interface (think ucontext), and yet others for a higher-level interface (think fibres). Interested parties will continue iterating on this proposal in a smaller group.
  • Attributes for likely and unlikely branches. When this proposal was first looked at (at the last meeting), the feedback was that instead of trying to place the attributes onto the conditions of branches themselves, they should be placed on the statement(s) that are being described as likely/unlikely to be reached. In this revision, the proposal author did that, but attempted to restrict the contexts in which such an attribute could be placed on a statement. EWG suggested allowing it on all statements instead, while also requesting that examples be added to clarify the semantics in a various scenarios.
  • An updated version of for loop exit strategies, which proposes to allow adding blocks of code at the end of a for loop that run when the loop exits by breaking (introduced by the keyword on_break), and when the loop runs to completion (introduced by on_complete). The only thing that has changed since the last revision of this proposal is the keywords – they were catch break and catch default in the previous version. EWG didn’t love the new keywords, either, and was generally lukewarm towards the proposal in terms of motivation, so it’s not clear if this is going anywhere.
  • Generalized unpacking and parameter pack slicing. This proposes a prefix slicing syntax: if T is a parameter pack, [N]T would denote the element at the Nth index of T; [N:M]T would denote a new parameter pack containing the elements from the Nth to the Mth indices of T. Additionally, the syntax can be applied to objects of any product type (roughly, a type that can be decomposed using structured bindings), in which case the object is considered to be a pack of its consituent objects (this is the “generalized unpacking” part, because it gives us a way to unpack product types into parameter packs using a simple syntax). EWG liked the goals, but felt that a proposal like this should be part of a global unified vision for metaprogramming. The proposal was sent to the Reflection Study Group, whose responsibilities going forward will include metaprogramming more generally, and which will consider it alongside other metaprogramming proposals.
    • It’s worth noting that there was another proposal on this topic in the pre-meeting mailing, that aimed to solve the problem by introducing a new type of expression resembling a for loop that would generate a parameter pack procedurally. It wasn’t presented because no one was available to champion it.
  • The Concurrency Study Group is working on SIMD support, and they consulted EWG on how that support should integrate with the type system. In particular, if a function has multiple SIMD variants, should they have different function types, potentially opening the door to overloading? This was the approach taken in the Transactional Memory TS (with transaction-safe and non-transaction-safe variants of a function). EWG discouraged further proliferation of this paradigm.
  • The constexpr operator. This is a facility that tells you whether or not you are executing a function in a constant expression context or not; it allows you to have different implementations for compile-time and runtime evaluation. EWG liked the idea, although the exact syntax remains to be nailed down. In addition, desire was expressed for a way to enforce that a constexpr function is only invoked at compile time.
  • constexpr_assert and constexpr_trace. These are proposed tools for debugging constexpr code, that allow you to direct the compiler to produce diagnostic/debugging output while performing constexpr evaluation. The idea was generally favourably received, though it was noted that for constexpr_trace, rather than having it produce output unconditionally, it would be useful to have a mechanism where it can accumulate output into a buffer, and then flush the buffer only if something goes wrong.
  • std::constexpr_vector<T>. The scope of what is allowed in constexpr functions has been steadily increasing, and it might seem that the logical next frontier is dynamic memory allocation. However, at least one implementer has performed extensive experimentation with allowing dynamic memory allocation in constexpr evaluation, and found that it could only be done at a drastic performance penalty. The reason is that the compiler is required to diagnose what would be undefined behaviour if it happens at runtime, during constexpr evaluation, and dynamic memory allocation opens up so many avenues to invoking undefined behaviour that the compiler needs extensive instrumentation to diagnose it. This proposal is an alternative to allowing full-blown dynamic allocation, that provides a specific, “magic”, vector-like type for use during constexpr evaluation, that should satisfy the large majority of use cases. EWG encouraged further exploration of this space.
  • Tuple-based for loops. This is an extension of range-based for loops to tuple-like types. Tuple-like types can be thought of as heterogeneous ranges (ranges whose elements are of different types), where the total number of elements and their types are known at compile time. Accordingly, a tuple-based for loop would be unrolled at compile time, and its body instantiated once for each element type. This gives rise to a simple and convenient syntax for processing tuple-like types, which has been desired for a long time (see e.g. the Boost.Fusion library). Concerns with this specific proposal included performance considerations (for example, it makes it very easy to write innocent-looking code that triggers a lot of template instantiations and is expensive to compile), and the fact that it didn’t generalize to some use cases (such as cases where you want the type of a result to depend on logic in your “loop”). Further exploration of the topic was encouraged.
  • Range-based for loop with initializer. This extends the C++17 selection statements with initializer feature to range-based for loops, allowing you to declare a variable “alongside” your iteration variable that is scoped to the loop and will live as long as the loop. In addition to facilitating better scoping hygiene (that is, making the scopes of variables as tight as possible), it provides a way to resolve a long-standing lifetime issue with range-based for loops. EWG requested that the author implement the proposal, and then bring it back, at which point, if no issues arise during implementation, approval is expected.
  • bit_sizeof and bit_offsetof. These are equivalents of the sizeof and offsetof operators (the latter is actually a macro) that return counts of bits, and are usable on bitfield members. EWG referred this proposal to the Reflection Study Group, as it may be implementable as a library on top of forthcoming reflection primitives.
  • Proposed changes to the Modules TS. I talk about this below.

Rejected proposals:

  • Implicit and anonymous return types. This proposed to allow declaring an anonymous structure in the return type of a function, as a way to allow it to return multiple named values (contrast with a tuple, which allows you to return multiple values but they are unnamed), without having to define a named structure in an enclosing scope. To facilitate out-of-line definitions for such functions, it also proposed using decltype(return) to denote “the previously declared return type” (since repeating the anonymous structure declaration in the function’s definition would both be repetitive, and, according to the current language rules, actually declare a second, distinct anonymous structure type). Besides being unconvinced about the motivation (viewing the alternatives of named structured and tuples as good enough), people pointed out various technical difficulties with the proposal. decltype(return), in particular, would further complicate C++’s function redeclaration rules, and introduce potential ambiguities and situations where a definition using decltype(return) could be well-formed or not depending on what other functions have declarations visible.
  • Initialization list symmetry. This tiny proposal would have allowed a trailing comma on the last element of a constructor’s initializer list (properly called a constructor-chain-initializer), to make member reordering and other refactorings easier. It was rejected on the basis that in C++ a comma is a separator, not a terminator, and it would be strange to allow it in a trailing position in this context but not other contexts (like function parameters, function arguments, or template arguments). It’s worth noting that C++ does already allow trailing commas in a few places, like enumerations and array initializers.
  • A qualified replacement for #pragma once. The proposal here is to standardize a variant of the widely supported #pragma once extension, spelt #once, which took an identifier and optional version as argument, and used them to solve #pragma once‘s longstanding problem of having to figure out whether two files are the same (which can sometimes be tricky in situations involving symbolic links and such). EWG felt that Modules would obsolete this feature, and as such it was not worth standardizing at this stage.

Concepts

This meeting marked the first significant design discussion about Concepts in EWG since a proposal to merge the Concepts TS into C++17 without modifications failed at the February 2016 meeting in Jacksonville.

The main topic of discussion was the Concepts TS revisited paper which proposed several design changes to Concepts:

  • Unifying function-like and variable-like concepts into a single concept definition syntax, as previously proposed. The unified syntax would drop the redundant bool keyword from concept bool, and the entities it would declare would be a kind unto their own, not variables or functions. The question of whether such entities can overload on the number and kinds of their template parameters (the original motivation for having function-like concepts) remains open, though it seems people are leaning towards not allowing overloading, arguing that if you have two concepts taking a different number or kind of template parameters, it’s probably clearer to give them different names (a canonical example is EqualityComparable<T> vs. EqualityComparableTo<T, U>; the latter becomes EqualityComparableTo<U> T in a constrained-parameter declaration, which reads very naturally: T must be of a type that’s equality-comparable to U). EWG encouraged continued exploration of this unification.
  • Changes to the redeclaration rules for constrained function templates. The Concepts TS provides multiple ways to express the same constrained function template. Currently, for purposes of determining whether two declarations declare the same function template, the shorthand forms are “desugared” to the long form (using requires-clauses only), and the usual redeclaration rules (which require token-for-token equivalence) are applied to the result. This means that e.g. a function template declared using the long form can be re-declared using one of the shorthand forms. The paper argued that this is brittle (among other things, it requires specifying the desugaring at the token level), and proposed requiring that redeclarations be token-for-token equivalent before desugaring. After extensive discussion, EWG was supportive of this change.
  • A minor change to the concept subsumption rules (that come into play during partial ordering of constrained function templates) where, for the purpose of determining whether two constraints are equivalent, the compiler does not “look into” atomic constraints and determine equivalence textually; two constraints are only equivalent if they refer to the same concept. This also garnered support.
  • Addressing the issue that subsumption checking can sometimes be expontential-time in the presence of disjunctions. The paper proposes addressing this by removing disjunctions, and instead introducing an explicit syntax for declaring concept refinement relationships, but the authors have since withdrawn that proposal, in part because it was quite controversial. It was pointed out that the previous change (not “looking into” atomic constraints during subsumption checking) will significantly alleviate the problem by reducing how often we run into the expontential case.
  • Modifying the abbreviated function template syntax to make it clear to readers that the function being declared is a template. Currently, the Concepts TS allowed an “abbreviated” syntax like void foo(Sortable& s); which declares a function template if Sortable is a concept. Many members of the committee and the larger C++ community expressed concern about having a template look exactly like a non-template, discriminated only by the result of name lookup on the argument types.

    EWG had a vigorous debate on this topic. On the one hand, people argued that templates and non-templates are fundamentally different entities, due to differences like the way name lookup works inside each, requiring typename in some contexts inside templates, and so on. Countering this, others argued that these differences are relatively minor, and that the long-term aim should be to make generic programming (programming with templates) be just like regular programming.

    One argument I found particularly interesting was: instead of having syntax to discriminate between templates and non-templates, why don’t we rely on tooling, such as having concept names syntax-colored differently from type names? I found this fairly convincing: since we are designing modern language features, it seems reasonable to design them with modern tools in mind. Then again, while many editors are capable of performing the sort of semantic highlighting contemplated here, programmers also spend a lot of time looking at code in non-editor contexts, such as in review tools, and I’ve yet to see one of those with semantic highlighting (although such a thing is conceivable).

    EWG did not reach a consensus on this topic. Several concrete proposals for syntax that would alert readers to the template-ness of an abbreviated function template were briefly discussed, but none of them were given serious consideration, because many people weren’t convinced of the need to have such syntax in the first place.

There was another proposal in the mailing concerning Concepts – one that I coauthored – that touched on the semantics of a concept name appearing twice in an abbreviated function template. It was not presented at this meeting for procedural reasons; I expect it will be presented at the next meeting in Toronto.

Definition Checking

There is one other topic related to Concepts that I’ve talked about before, and would like to touch on again: definition checking. To recap, this involves having the compiler check an uninstantiated template definition to make sure that it only uses its template parameters in ways allowed for by their constraints. In principle, definition checking combined with checking constraints at call sites (which the Concepts TS already does) should completely eliminate the possibility of compiler errors with instantiation backtraces: either the error is that the caller is not passing in types that meet the constraints, in which case the error pertains to the call site only; or the error is that the implementation uses the template parameters in ways not provided for by the constraints, in which case the error pertains to the uninstantiated definition site only.

As I described in my Jacksonville report, one of the reasons Concepts failed to make C++17 is that people had concerns about whether concepts in their current form are conducive to definition checking. However, that was not the only reason, and since Jacksonville I’ve increasingly heard the sentiment expressed that definition checking is a hard problem, and we should not hold up Concepts while we figure out how to do it. To quote the “vision for C++20” paper that I talked about above:

At the risk of sounding like a broken record, I will repeat a particular point: we need to throw definition checking under the bus. If we insist on having it, we will probably get nothing in C++20, and chances are we’ll get nothing in C++23. Such a trade-off is unacceptable. The benefits of Concepts as proposed far outweigh the benefits of definition checking, and most users wouldn’t care less about not having definition checking.

While I personally disagree with the sentiment that “most users wouldn’t care less about not having definition checking” – I believe it’s actually a critical part of a complete generic programming design – I do agree that Concepts is still very useful without it, and having to wait for Concepts until C++23 or beyond on its account would be very unfortunate.

A year ago, I was quite hopeful that we could make progress on the technical problems surrounding definition checking in time to make appropriate revisions to the Concepts TS (to, for example, tweak the way concepts are defined to be more amenable to definition checking) and get the result into C++20. Today, based on statements like the above, I am significantly less hopeful. My prediction is that, at this point, we’ll get Concepts in C++20, without any changes geared towards definition checking, and then maybe at some point in the future we’ll get some form of definition checking, that will be constrained by choices made in the Concepts TS as currently written. In this scenario, the desirable property I described above – that all errors are caught either purely at the call site, or purely at the definition site – which, I’ll note, is a property that other languages like Haskell and Rust do have – is unlikely to be achieved.

Modules

EWG spent half a day on the Modules TS. (I summarized the procedural developments above.)

The first main topic of discussion was a name lookup issue that came up during wording review of the Modules TS working draft in the Core Working Group. The issue concerns situations like this:

  • A module A defines a template foo, which uses an operation op on its argument.
  • A module B includes a non-modular (“legacy”) header that defines a type S and provides operation op for it.
  • B imports A, and defines a template bar that invokes foo with S as an argument, but still in a dependent context (so as not to trigger immediate instantiaion of foo).
  • A translation unit C imports B and instantiates bar.

What happens here is, the instantiation of foo happens in the context of C, where S‘s op is not visible. This could lead to:

  • A compiler error, if no other viable definition of op is visible.
  • A different (viable) definition of op than the intended one being silently called.
  • An ODR violation (undefined behaviour) if another translation unit has already instantiated foo, and op resolved to something else there.

Note that if the modules are replaced with headers, and imports with #includes, this setup works just fine.

To work around this, the programmer can do one of two things:

  • Have B export S‘s op, so it’s visible in all units that import B. There’s syntax for doing this even though S is defined inside a non-modular header.
  • Include the non-modular header that defines S and its op from C.

Neither of these is particularly satisfying. The first, because it involves repeating the declaration of op; the second, because S may be an implementation detail of B that C can’t be expected to know anything about.

The implementers of Modules at Microsoft argued that they haven’t run into this situation very much while deploying their implementation in a large codebase, and suggested shipping Modules v1 as a PDTS without addressing this issue, to gather feedback about how widespread of a problem it is. The Clang implementers stated that they had run into this, and needed to adjust the semantics of their modules implementation to deal with it. In the end, there was no consensus on changing the Modules TS semantics to deal with this problem before releasing the PDTS.

The other main topic of discussion was a paper containing proposed changes to the Modules TS from the Clang implementers – specifically the ones approved in Jacksonville for which there was confusion about whether they were meant to apply to Modules v1:

  • Requiring the module declaration to be the first declaration in a module file. Currently, it doesn’t have to be, and preceding declarations belong to the global module. The proposal would come with a mechanism to “reopen” the global module after the module declaration and place declarations in it. Apart from implementation considerations (from which point of view there are arguments on both sides), the motivation is readability: making it immediately clear to the reader that a file is a module file. There was no consensus for making this changes in Modules v1.
  • Introducing syntax to differentiate the module declaration for a module interface file from the module declaration for a module implementation file. EWG expressed support for this for Modules v1, and a preference to add the extra syntax to the interface declaration. No specific syntax was chosen yet.
  • Introducing syntax for module partitions (module interfaces spread across multiple files). EWG supported putting this in Modules v1 as well, though again no specific syntax was yet chosen.

As stated above, the hope is that Modules v1, as amended with the approved changes I described, can ship as a PDTS at the next meeting in Toronto.

Other Working Groups

The Library Working Group spent the week, including most evenings, heroically processing the large quantity of C++17 CD comments that concerned the standard library (a lot of them relating to the recently-merged Filesystem TS, though there were many others too), so that we could stay on schedule and send C++17 out for its DIS ballot at the end of the week (which we did).

The Library Evolution Working Group was working through its large backlog of proposed new library features. As much as I’d love to follow this group in as much detail as I follow EWG, I can’t be in two places at once, so the best I can do is point interested readers to the mailings to check out library proposals.

Regarding the various Study Groups, I’ve largely mentioned as much as I know about their progress in the Technical Specifications section above, but I’ll say a few more words about a couple of them:

SG 7 (Reflection)

SG 7 looked at two proposals for static reflection that can be thought of as alternatives to the proposal approved earlier by the group (and approved this week by EWG).

Both proposals are essentially “isomorphic” to the approved proposal in terms of what can be reflected, they just propose doing the reflection with a different syntax, and in particular with a syntax that represents meta-objects (reflected information about program entities) as values rather than types.

The differences between the two proposals are mostly just syntax and interface, e.g. the first uses a member function interface for operations on the meta-objects, while the second one uses a free function interface.

In addition, the author of the second proposal presented an extension (not in the paper) that would essentially allow generating source code from compile-time strings, which would be a very powerful and general metaprogramming facility. It was pointed out that, while we may want such a general facility for advanced metaprogramming use cases, it seems like overkill for the reflection use cases being considered.

The outcomes of the session were that: there is interest in moving towards reflection through values rather than through types; that the already-approved proposal (which does it through types) should nonetheless go forward as-is (which it did, with EWG approving it the next day); that a free function interface is preferable to a member function interface; and that the group should aim to (also) standardize more general metaprogramming features.

This latter – expanding the purview of SG 7 from just reflection, to metaprogramming more generally – is a deliberate change supported by the committee leadership. The group may be renamed “Reflection and Metaprogramming” or similar in due course.

SG 14 (Game Development & Low-Latency Applications)

SG 14 did not meet at GDC this year like it did last year, because this year’s GDC was the same week as the committee meeting I’m writing about 🙂

They do hold regular teleconferences (see the mailing list for details), and the latest status of their various proposals can be found in this summary paper.

Over the past year, the group has also been courting the interest of the embedded programming community, which is interested in many of the same issues (memory-constrained environments, hard/soft real-time applications, avoidance of dynamic memory allocation, etc.) as the existing consituencies represented in SG 14.

Next Meeting

The next meeting of the Committee will be in Toronto, Canada (which is where I’m based!), the week of July 10th, 2017.

Conclusion

C++17 is effectively out the door, with its Draft International Standard sent out for ballot, and the official release expected later this year.

Development on C++20 is well under way, with numerous core language and library features already earmarked for it, and several Technical Specifications expected to be merged into it. A proposal for an overall vision for the release aims to focus the committee’s efforts on four headliner features – Concepts, Modules, Ranges, and Networking. That is, of course, not a guarantee these features will be in C++20 (nor is it intended to exclude other features!), but I believe with some luck and continued hard work we can make part of all of that plan a reality.

Modules, in particular, are expected to be a game-changer for C++. Whether or not they make C++20, they will be available as a Technical Specification very soon (possibly as soon as later this year), and they are already available for experimentation in Clang and MSVC today.

Stay tuned for continued reporting on C++ standardization on my part!

Advertisements

About botondballo

I am a recent graduate of the University of Toronto, with a degree in Computer Science. I currently work for Mozilla as a software engineer.
This entry was posted in c++, programming and tagged , , . Bookmark the permalink.

8 Responses to Trip Report: C++ Standards Meeting in Kona, February 2017

  1. jmckesson says:

    > then maybe at some point in the future we’ll get some form of definition checking

    Highly unlikely. I pretty much guarantee that, if Concepts hits C++ without definition checking, or a significant move towards it, then C++ will *never* have definition checking.

    After all, the change about atomics (where two concepts are equal only if they use the same sub-concepts) makes definition checking fundamentally unworkable. If you and some other library independently define a `Regular` concept, and they’re essentially copies of the Range TS’s `Regular` concept, definition checking will find that the two concepts are different. So my template function that uses my `Regular` concept cannot pass it to your template function that uses your `Regular` concept, since it doesn’t recognize them as being equivalent.

    No, this is a case where the anti-definition-checking people have outmaneuvered us, by poisoning Concepts with seemingly good features that increasingly make definition checking dysfunctional. Don’t hold your breath at ever seeing definition checking.

    • botondballo says:

      The change you’re referring to, about when two concepts are considered equivalent, pertains to the subsumption rules used during partial ordering of function templates. A future definition checking feature need not use the same subsumption rules as partial ordering.

      I think there’s still a possibility of getting a definition checking feature that catches *some* errors at definition time. It just won’t catch *all* errors.

  2. Daniel says:

    This website has been my go-to source of information about the current state of C++ standardization for quite a while now, and I’m sure it’s the same for many others.

    Thank you and keep it up!

  3. Thomas K says:

    Thanks for the report! One correction: range-based for wit initializer is http://wg21.link/p0614, not p0616 as stated in the text.

  4. Pingback: C++17 (prawie) formalnie gotowe… – MalLog

  5. Pingback: Trip Report: C++ Standards Meeting in Toronto, July 2017 | There's Waldo!

  6. Pingback: Trip Report: C++ Standards Meeting in Albuquerque, November 2017 | There's Waldo!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s