Botond Ballo: Trip Report: C++ Standards Meeting in Kona, October 2015 |
Project | What’s in it? | Status |
C++14 | C++14 | Published! |
C++17 | Very much in flux. Significant language features under consideration include default comparisons, operator. , a unified function call syntax, coroutines, and concepts. |
On track for 2017 |
Filesystems TS | Standard filesystem interface | Published! |
Library Fundamentals TS I | optional , any , string_view and more |
Published! |
Library Fundamentals TS II | source code information capture and various utilities | Voted out for balloting by national standards bodies |
Concepts (“Lite”) TS | Constrained templates | Publication imminent |
Parallelism TS I | Parallel versions of STL algorithms | Published! |
Parallelism TS II | TBD. Exploring task blocks, progress guarantees, SIMD. | Under active development |
Transactional Memory TS | Transaction support | Published! |
Concurrency TS I | improvements to future , latches and barriers, atomic smart pointers |
Voted out for publication! |
Concurrency TS II | TBD. Exploring executors, synchronic types, atomic views, concurrent data structures | Under active development |
Networking TS | Sockets library based on Boost.ASIO | Design review completed; wording review of the spec in progress |
Ranges TS | Range-based algorithms and views | Design review completed; wording review of the spec in progress |
Numerics TS | Various numerical facilities | Beginning to take shape |
Array Extensions TS | Stack arrays whose size is not known at compile time | Direction given at last meeting; waiting for proposals |
Reflection | Code introspection and (later) reification mechanisms | Still in the design stage, no ETA |
Graphics | 2D drawing API | Waiting on proposal author to produce updated standard wording |
Modules | A component system to supersede the textual header file inclusion model | Microsoft and Clang continuing to iterate on their implementations and converge on a design. The feature will target a TS, not C++17. |
Coroutines | Resumable functions | At least two competing designs. One of them may make C++17. |
Contracts | Preconditions, postconditions, etc. | In early design stage |
Last week I attended a meeting of the ISO C++ Standards Committee in Kona, Hawaii. This was the second committee meeting in 2015; you can find my reports on the past few meetings here (June 2014, Rapperswil), here (November 2014, Urbana-Champaign), and here (May 2015, Lenexa). These reports, particularly the Lenexa one, provide useful context for this post.
The focus of this meeting was primarily C++17. There are many ambitious features underway for standardization, and the time has come to start deciding what which of them will make C++17 and which of them won’t. The ones that won’t will target a future standard, or a Technical Specification (which can eventually also be merged into a future standard). In addition, there are a number of existing Technical Specifications in various stages of completion.
After C++11, the committee adopted a release train model (much like Firefox’s) for new revisions of the C++ International Standard. Instead of targetting specific features for the next revision of the standard, and waiting until they are all ready before publishing the revision (the way it was done in C++11, which ended up being published 13 years after the previous major revision, C++98), new revisions are released on a three-year train (thus C++14, C++17, C++20, etc.), and a feature is either ready in time to make a particular train, or not (in which case, too bad; it can ride the next train).
As such, there isn’t a list of features planned for C++17 per se. Rather, there are many features in the works, and some will be ready to ride the C++17 train while others will not. More specifically, the committee plans to release the first draft of C++17 for balloting by national standards bodies, called the Committee Draft or CD, at the end of the June 2016 meeting in Oulu, Finland. (This is the timeline required to achieve a publication date in 2017.) This effectively means that for a feature to be in C++17, it must be voted in at that meeting at the latest.
As a recap, here are the features that have already been voted into C++17 at previous meetings:
static_assert(condition)
without a messageauto var{expr};
template <...> typename Name
std::uncaught_exceptions()
u8
character literalsunique_ptr
std::reference_wrapper
trivially copyablenoexcept
in containersvoid_t
alias templateinvoke
function templatesize()
, empty()
, and data()
functionspair
and tuple
bool_constant
shared_mutex
I’d classify all of the above as “minor” except for folding expressions, which significantly increase the expressiveness of variadic template code.
Here are the features that have been voted into C++17 at this meeting:
register
keyword, while keeping it reserved for future useoperator++
for bool
__has_include()
, a portable way of testing for the presence of a header. (The original proposal also included a __has_attribute()
facility that would portably test for support for an attribute, but EWG rejected this on the basis that it encourages wrapping attributes into macros, and will have limited utility once compiler support for standard attributes becomes universal.)is_convertible
. The variable template version’s name is the original trait’s name suffixed with _v
. For example, is_convertible::value
can now be written is_convertible_v
. This feature is also in the Library Fundamentals TS II, but it’s so popular that people wanted in C++17 as well.as_const()
, a function that provides a constant view of its argumentstd::owner_less
more flexible
lock_guard
conjunction
, disjunction
, and negation
.not_fn
was rejected on the basis that the proposal also included removing the legacy not1
and not2
facilities without deprecating them first, and there was opposition to this. An updated version of the proposal that changes the removal to deprecation is expected to pass at the next meeting.By and large, this is also minor stuff.
Finally, the most interesting bunch: features that haven’t been voted into C++17 yet, but that people are working hard to try and get into C++17.
I’d like to stress that, while obviously the committee tries to standardize features as expeditiously as is reasonable, there is a high quality bar that has to be met for standardization, and a feature isn’t in C++17 until it’s voted in. The features I mention here all have a chance of making C++17 (some better than others), but there are no guarantees.
The Concepts Technical Specification (informally called “Concepts Lite”) has been voted for publication in July of this year, and the release of the published TS by ISO is imminent.
The idea behind Technical Specifications is that they give implementers and users a chance to gain experience with a feature, without tying the committee’s hands by standardizing the feature which makes it very difficult to change it in non-backwards-compatible ways. The eventual fate envisioned for a TS is being merged into a future standard, possibly with modifications motivated by feedback from implementers and users.
The question of whether the Concepts TS should be merged into C++17 thus naturally came up. This was certainly the original plan in 2012, when the decision was made to pursue Concepts Lite as a TS aimed for publication in 2014; people then envisioned the TS as being ripe for merger by C++17. Today, with the publication of the TS having slipped to 2015, and the effective deadline for getting changes into C++17 being mid-2016, the timeline looks a bit tighter.
The Concepts TS currently has one complete implementation (modulo bugs), in GCC trunk, which will make it into a release (GCC 6) next year. This, currently experimental, implementation has already been used to gain experience with the feature. Most notably, the Ranges Technical Specification, which revamps significant parts of the C++ Standard Library using Concepts, has an implementation that uses Concepts (in contrast to the previous implementation which emulated Concepts in C++11) and compiles with GCC trunk.
Based on this and other experience, several committee members have argued that Concepts is ripe for standardization in C++17. Others have expressed various concerns about the current design, and argued on this basis that Concepts is not ready for C++17:
This last point deserves some elaboration.
When you write a reusable piece of code, such as a function or class, you’re defining an interface between the users of the code, and its implementation. When the function or class is a template, the interface includes requirements on the types (or values) of the template parameters, which are checked at compile time.
Prior to Concepts, these requirements were implicit; you could document the requirements, and you could approximate making them explicit in code by using certain techniques like enable_if
, but there was no first-class language support for making them explicit in code. As a result, violations of these requirements – either on the user side by passing template arguments that don’t meet the requirements, or on the implementation side by using the template arguments in ways that go beyond the requirements – would only be caught at instantiation time, that is, when the template is instantiated with concrete arguments for a particular use site. Compiler errors resulting from such violations typically come with long instantiation backtraces, and are notoriously difficult to understand.
Concepts Lite allows us to express these requirements explicitly in code, and to catch violations on the user side “early”, by checking the concrete template arguments passed at a use site against the requirements, without having to look at the implementation of the template. The resulting compiler errors are much easier to understand, and do not contain instantiation backtraces.
However, with the current Concepts Lite design, violations of the requirements on the implementation side – that is, using the template arguments in ways that go beyond the specified requirements – continue to be caught only at instantiation time, and produce hard-to-understand errors with long backtraces. A complete Concepts design, such as the one originally proposed for C++11, includes checking the body of a template against the specified requirements independently of any particular instantiation, to catch implementation-side errors “early” as well; this is referred to as separate checking of template definitions.
Concepts Lite doesn’t currently provide for separate checking of template definitions. Claims have been made that it can be extended to support this, but as this is a difficult-to-implement feature, some would like to see stronger evidence for this (such as a proof-of-concept implementation, or a detailed description of how one would implement it) prior to standardizing Concepts Lite and thus locking us into the current design.
No decision about merging Concepts Lite into C++17 has been made at this meeting; I expect that the topic will continue to be discussed over the next two meetings, with a decision made no later than the June 2016 meeting.
The first Parallelism TS, which contains parallel versions of standard algorithms, and was published earlier this year, will be proposed for merger into C++17.
The Filesystem TS, the first Library Fundamentals TS, and the Transactional Memory TS have also been published earlier this year, and could plausibly be proposed for merger into C++17, although I haven’t heard specific talk of such proposals yet.
TS’es that are still in earlier stages of the publication pipeline, such as the Concurrency TS, will almost certainly not make C++17.
As I’ve described in previous posts, there are three competing coroutines proposals in front of the committee:
await
proposal” after one of the keywords it introduces.I talk more about the tradeoffs between stackful and stackless coroutines in my Urbana report, and describe the hybrid approach in more detail in my Lenexa report.
In terms of standardization, at the Urbana meeting the consensus was that stackful and stackless coroutines should advance as independent proposals in the form of a Technical Specification, with a possible view of unifying them in the future. Developments since then can be summed up as follows:
await
proposal has advanced to a stage where it is fully fleshed out, has standard wording, and the Core Working Group has begun reviewing the standard wording.Given this state of affairs, and particularly the advanced stage of the await
proposal, the question of whether it should be standardized in C++17, rather than a TS, came up. A poll was held on this topic in the Evolution Working Group, with the options being (1) standardizing the await
proposal in C++17, and (2) having a TS with both proposals as originally planned. There wasn’t a strong consensus favouring either of these choices over the other; opinion was mostly divided between people who felt we should have some form of coroutines in C++17, and people who felt there was still room for iteration on and convergence between the proposals, making a TS the more appropriate vehicle.
For now, the Core Working Group will continue reviewing the wording of the await
proposal; the ship vehicle will presumably be decided by a vote of the full committee at a future meeting.
Contracts are a way to express preconditions, postconditions, and other runtime requirements in code, with a view toward opening up use cases such as:
Initial proposals in the area tended to cater to one or more of these use cases to the detriment of others; guidance from the committee was to aim for a unified proposal. While no such unified proposal has been written yet, the authors of the original proposal and other interested parties have been hard at work trying to solve some of the technical problems involved. I give some details further down.
Given the relatively early stage of these efforts, it’s in my opinion unlikely that they will result in a proposal that makes it into C++17. However, it’s not out of the question, if a written proposal is produced for the next meeting, and its design and wording reviews go sufficiently smoothly.
Overloading operator dot (the member access operator) allows new forms of interface composition that weren’t possible before.
A proposal for doing so was approved by EWG at the previous meeting; it’s currently pending wording review by CWG.
Another proposal that brings even more expressive power was looked at this meeting; it was sent to the Reflection Study Group as the abilities it unlocks effectively constitute a form of reflection.
The original proposal is slated to come up for a vote to go into C++17 once it passes wording review; however, some object to it on the basis that reflection facilities (such as those that might be produced by iterating on the second proposal) would supersede it. Therefore, I would classify its fate in C++17 as uncertain at this point.
Beyond the big-ticket items mentioned above, numerous smaller language features may be included in C++17. For a list, please refer to the “Evolution Working Group” section below. Proposals approved by EWG at this meeting are fairly likely to make C++17, as they only need to go through wording review by the Core Working Group before being voted into C++17. Proposals deemed by EWG to need further work face a bit of a higher hurdle, as an updated proposal would need to go through both design and wording reviews before being voted into C++17.
Modules are possibly the single hottest feature on the horizon for C++ right now. Everyone wants them, and everyone agrees that they will solve very significant problems ranging from code organization to build times. They are also a very challenging feature to specify and implement.
There are two work-in-progress Modules implementations: one in Microsoft’s compiler, and one in Clang, developed primarily by Google. The two implementations take slightly different approaches, and the implementers have been working hard to try to converge their designs.
The Evolution Working Group held a lengthy design discussion about Modules, which culminated in a poll about which of two possible ship vehicles is more appropriate: C++17, or a Technical Specification. A Technical Specification had a stronger consensus, and this is what is currently being pursued. This means Modules are not currently slated for inclusion in C++17. It’s not inconceivable for this to change, if the implementors make very significant progress before the next meeting and convince the committee to change its mind; in my opinion, that’s unlikely to happen.
I talk about the technical issues surrounding Modules in more detail below.
Major language features that I haven’t mentioned above, such as reflection, aren’t even being considered for inclusion for C++17.
As usual, I spent practically all of my time in the Evolution Working Group, which spends its time evaluating and reviewing the design of proposed language features.
EWG categorizes incoming proposals into three rough categories:
Accepted proposals:
inline
, in which case the declaration counts as a definition. (The declaration must then include any initializer.) This is analogous to inline functions, and spares the programmer from having to provide an out-of-line definition in a single translation unit (which can force an otherwise header-only library to no longer be header-only, among other annoyances). The proposal was accepted, with two notable changes. First, to reduce verbosity, constexpr
will imply inline
. Second, namespace-scope variables will only be allowed to be inline
if they are also const
. The motivation for the second change is to discourage proliferation of mutable global state; it passed despite objections from some who thought it was complicating the rules with little benefit.constexpr
context. These have good use cases, and there isn’t any compelling motivation to disallow them; the proposal had near unanimous support.throw()
at the end of a function declaration. These have been deprecated since C++11 introduced noexcept
. throw()
is kept as a (deprecated) synonym for noexcept(true)
.constexpr_if
, which was called static_if
in previous iterations of the proposal. It’s like an if
statement, but its condition is evaluated at compile time, and if it appears in a template, the branch not taken is not instantiated. This is neat because it allows code like constexpr_if (/* T is refcounted */) { /* do something */ } constexpr_else { /* do something else */ }
; currently, things like this need to be accomplished more verbosely via specialization.EnumName{42}
syntax. This was already allowed using the EnumName(42)
syntax, but it was considered a narrowing conversion which is not allowed with the {}
syntax. This allows using an enumeration as an opaque/strong typedef for an integer type more effectively. It passed despite objections that a full opaque typedefs proposal would make using enums for this purpose unnecessary.f(x, y)
can resolve to x.f(y)
if regular name lookup finds no results for f
. This is #3 out of the six design alternatives presented in the original proposal. It satisfies the proposal’s primary use case of making it easier to write generic code using Concepts, by allowing concepts to to require the non-member syntax to work (and have template implementations use the non-member syntax), while a type can be made to model a concept using either member or non-member functions. The other direction (x.f(y)
resolving to f(x, y)
if member name lookup finds no results for f
) was excluded because it was too controversial, as it enabled writing rather brittle code that’s susceptible to “action at a distance”.await
proposal (a.k.a. resumable functions / stackless coroutines). Most notably, EWG settled on the keyword choices co_await
, co_yield
, and co_return
; the proposed alternative of “soft keywords” that tried to allow using await
and yield
without making them keywords, was rejected on the basis that “the difficulty of adding keywords to C++ is a feature”. The various modifications listed in this paper and this one were also accepted.(I didn’t list features which also passed CWG review and were voted into C++17 at this meeting; those are listed in the the C++17 section above.)
Proposals for which further work is encouraged:
*this
by value. Currently, capturing this
captures the containing object by reference; in situations where capture by value is desired (for example, because the lambda can outlive the object), a temporary copy of the object has to be made and then captured, which is easy to forget to do. The paper proposes introducing two new forms in the capture list: *this
, to mean “capture the containing object by value”, and *
, to mean “capture all referenced variables including the containing object by value”. EWG advised going forward with the first one only (*
looks like “capture by pointer”, and we don’t need a third kind of default capture).alignas(N)
, but this does not affect dynamic allocation; the proposal makes it do so. EWG agreed that this should be fixed, but there were some concerns about backward-compatibility; the proposal author will iterate on the proposal to address these concerns.int
, the inherited operator +
could be “aliased” to take and return your derived type instead. EWG liked the idea of function aliases, and encouraged developing it into an independent proposal. Regarding opaque aliases, EWG felt inheritance wasn’t the appropriate mechanism; in particular, deriving from built-in types opens up a can of worms (e.g. “are the operations on int
virtual?”). Instead, wrapping the underlying type as a member should be explored as the mechanism for creating opaque aliases. This can already be done today, if you define all the wrapped operations yourself; the language should make that easier to do. It was pointed out that reflection may provide the answer to this.operator .
, obj.member
would resolve to obj.operator.(f)
, where f
is a compiler-generated function object that accepts an argument a
of any type, and returns a.member
. (Similarly, obj.func(args)
would be transformed in the same way, with the function object returning a.func(args)
). This proposal has more expressive power than the existing “operator dot” proposal, allowing additional patterns like a form of duck typing (see the paper for a list). EWG liked the abilities this would open up, but wasn’t convinced that “operator dot” was the right spelling for such a feature. In addition, it was pointed out that a lot of these abilities fall under the purview of reflection; EWG recommended continuing to pursue the idea in the Reflection Study Group.[[pure]]
attribute, which would apply to a function and indicate that the function had no side effects. Everyone wants some form of this, but people disagree on the exact semantics, and how to specify them. The prevailing suggestion seemed to be to specify the behaviour in terms of the “abstract machine” (an abstraction used in the C++ standard text to specify behaviour without getting into implementation-specific details), and to explore standardizing two attributes with related semantics: one to mean “the function can observe the state of the abstract machine, but not modify it”, and another to mean “the function cannot observe the state of the abstract machine, except for its arguments”. To illustrate the difference, a function which reads the value of a global variable (which could change between invocations) would satisfy the first condition, but not the second; such a function has no side effects, but different invocations can potentially return different values. GCC has (non-standard) attributes matching these semantics, [[gnu::pure]]
and [[gnu::const]]
, respectively.template
. This was almost approved, but then someone noticed a potential conflict with the Concepts TS. In the Concepts TS, auto
is treated as a concept which is modelled by all types, and in most contexts where auto
can be used, so can a concept name. Extending those semantics to this proposal, the meaning of template
ought to be “a template with a single non-type template parameter whose type is deduced but must satisfy the concept ConceptName
“. The problem is, template
currently has a different meaning in the Concepts TS: “a template with a single type template parameter which must satisfy ConceptName
. EWG encouraged the proposal author to work with the editor of the Concepts TS to resolve this conflict, and to propose any resulting feature for addition into the Concepts TS.
template
vector(Iter begin, Iter end) -> vector>;
vector
is constructed without explicit template arguments and the constructor arguments have type Iter
, deduce vector
‘s template argument to be ValueTypeOf
. The proposal author recommended allowing both forms of deduction, and EWG, after discussing both at length, agreed; the author will write standard wording for the next meeting.for
loop syntax to run different code when the loop exited early (using break
) than when the loop exited normally. This avoids needing to save enough state outside the loop’s scope to be able to test how the loop exited, which is particularly problematic when looping over ranges with single-pass iterators. EWG agreed this problem is worth solving, but thought the proposal wasn’t nearly well baked enough. A notable concern was that the proposed syntax, if for (...) { /* loop body */} { /* normal exit block */ } else { /* early exit block */ }
had the reverse of the semantics of python’s existing for ... else
syntax, in which else
denotes code to be run if the loop ran to completion.[[using(ns), foo, bar, baz]]
, which would be a shorthand for [[ns::foo, ns::bar, ns::baz]]
. EWG liked the idea, but felt some more work was necessary to get the lookup rules right (e.g. what should happen if an attribute name following a using
is not found in the namespace named by the using
).[[unused]]
, [[nodiscard]]
, and [[fallthrough]]
attributes, whose meanings are roughly “if this entity isn’t used, that’s intentional”, “it’s important that callers of this function use the return value”, and “this switch
case deliberately falls through to the next”. The purpose of the attributes is to allow implementations to give or omit warnings related to these scenarios more accurately; they all exist in the wild as implementation-specific attributes, so standardizing them makes sense. EWG liked these attributes, but slightly preferred the name [[maybe_unused]]
for the first, as [[unused]]
might wrongly suggest the semantics “this should not be used”. The notion that [[nodiscard]]
should be something other than an attribute (such as a keyword) so that the standard can require a diagnostic if the result of a function so marked is discarded, came up but was rejected.auto {x, y, z} = expr;
where the type of expr
was a tuple-like object, whose elements would be bound to the variables x
, y
, and z
(which this construct declares). “Tuple-like objects” include std::tuple
, std::pair
, std::array
, and aggregate structures. The proposal lacked a mechanism to adapt a non-aggregate user-defined type to be “tuple-like” and work with this syntax; EWG’s feedback was that such a mechanism is important. Moreover, EWG recommended that the proposal be expanded to allow (optionally) specifying types for x
, y
, and z
, instead of having their types be deduced.a == b
into something like a.foo == b.foo && a.bar == b.bar
at each call site, performing lookup for each member’s comparison operator at the call site. As these lookups can yield different results for different call sites, the comparison can have different semantics at different call sites. People didn’t like this; several alternatives were proposed along the lines of generating a single, canonical comparison operator for a type, and using it at each call site. An updated proposal that formalizes one of these alternatives is expected at the next meeting.Rejected proposals:
void
be an object type, so that you can use it the way you can use any object it (that is, you can instantiate it, form a reference to it, and other things currently forbidden for void
). The motivation was to ease the writing of generic code, which oftens needs to specialize templates to handle void
correctly. EWG agreed the problem was worth solving, but didn’t like this approach; the strongest objections revolved around situations where the inability to use void
in a particular way is an important safeguard, such as trying to delete a void*
, or trying to perform pointer arithmetic on one, both of which would have to be allowed (or otherwise special-cased) under this scheme.this
, and allow calling such functions using the member function call syntax. This is essentially an opt-in version of the “x.f(y)
can resolve to f(x, y)
” half of the unified function call syntax proposal, which is the half that didn’t pass. It was shot down mostly for the same reasons that the full (no opt-in) version was (concerns about making code more brittle), but even proponents of a full unified call syntax opposed it because they felt an opt-in policy was too restrictive (not allowing existing free functions to be called with a member syntax), and that the safety objectives that motivated opt-in could be better accomplished through Modules.noexcept(auto)
. This wasn’t so much a rejection, as a statement from the proposal author that he does not intend to pursue this proposal further, in spite of EWG having consensus for it at the last meeting. A notable reason for this change in course was the observation that authors of generic code who would benefit most from this feature, often want the function’s return expression to appear in the declaration (such as in the noexcept-specification) for SFINAE purposes.std::uncaught_exceptions()
, previously added to C++17, with a different API that the author argued is harder to misuse. EWG didn’t find this compelling, and there was no consensus to move forward with it.A proposal for looping simultaneously over multiple ranges was not heard because there was no one available to present it.
I talked above about the target ship vehicle for Modules being a Technical Specification rather than C++17. Here I’ll summarize the technical discussion that led to this decision.
Modules enable C++ programmers to fundamentally change how they structure their code, and derive many benefits as a result, ranging from improved build times to better tooling. However, programmers often don’t have the luxury of making such fundamental changes to their existing codebases, so there is an enormous demand for implementations to support paradigms that allow reaping some of these benefits with minimal changes to existing code. A big open question is, to what extent should this set of use cases – transitioning existing codebases to a modular world – influence the design of the language feature as standardized, versus being provided for in implementation-specific extensions. Having different answers for this question is the largest source of divergence between the two current Modules implementations.
The most significant issue that this question manifests itself in, is whether modules should “carry” macros; that is, whether macros should be among the set of semantic entities that one module can export and another import.
There are compelling arguments on both sides. On the one hand, due to their nature (being preprocessor constructs, handled during a phase of translation when no syntactic or semantic information is yet available), macros hugely complicate the analysis of C++ code by tools. The vast majority of their uses cases now have non-preprocessor-based alternatives, from const
variables and inline
functions introduced back in the days of C, to reflection features like source code information capture (to replace things like __FILE__
) being standardized today. They are widely viewed as a scourge on the language, and a legacy feature that has no place in new code and does not deserve consideration when designing new language features. As a result, many argue that Modules should not have first-class support for macros. This is the position reflected in Microsoft’s implementation. (It’s important to note that Microsoft’s implementation does have a mechanism for dealing with macros to support transitioning existing codebases (specifically, there exists a compiler flag that can be used when compiling a module that, in addition to generating a module interface file, generates a “side header” containing macro definitions that a consumer of the module can #include
in addition to importing the module), but this is strictly an extension and not part of the language feature as they propose it.)
On the other hand, practically all existing large codebases include components that use macros in their interfaces – most notably system headers – and this is unlikely to change in the near future. (As someone put it, “no one is going to rewrite all of POSIX to not use macros any time soon”.) To allow modularizing such codebases in a portable way, many argue that it’s critical that Modules have first-class, standardized support for macros. This is the position reflected in Clang’s implementation.
Factoring into this debate is the state of progress of the two implementations. Microsoft claims to have a substantially complete implementation of their design (where modules do not carry macros), to be released as part of Visual C++ 2015 Update 1, and has submitted a paper with standard wording to the committee. The Clang folks have not yet written such a paper or wording for their design (where modules do carry macros), because they feel their implementation is not yet sufficiently complete that they can be confident that the design works.
EWG discussed all this, and recognized the practical need to support macros in some way, while also recognizing that there is a lot of demand to have some form of Modules available for people to use as soon as possible. A preference was expressed for standardizing Microsoft’s “ready to go” design in some form, while treating the additional abilities conferred by Clang’s design (namely, modules carrying macros) as a possible future extension. The decision to pursue Microsoft’s design as a Technical Specification rather than in C++17 was made primarily because at this stage, we cannot yet be confident that Clang’s design can be expressed as a pure, no-breaking-changes extension to Microsoft’s design. A Technical Specification comes with no guarantee that future standards will be compatible with it, making it the safer and more appropriate choice of ship vehicle.
Later in the week, there was an informal evening session about the implementation of Modules. Many interesting topics were brought up, such as whether the result of compiling a module is suitable as a distribution format for code, and what the implications of that are for things like DRM. Such topics are strictly out of scope of standardization by the committee, but it’s good to hear implementers are thinking about them.
Two evening sessions were held on the topic of contract programming, to try to make progress towards standardization. Building on the consensus from the previous meeting that it should be possible to express contracts both in the interface of a function (such as a precondition stated in the declaration) and in the implementation (such as an assertion in the function body), the group tackled some remaining technical challenges.
The security implications of having a global “contract violation handler” which anyone can install, were discussed: it opens up an attack vector where malicious code sets a handler and causes the program to violate a contract, leading to execution of the handler. It was observed that two existing language features, the “terminate handler” (called when std::terminate()
is invoked) and the “unexpected handler” (called when an exception is thrown during stack unwinding) have a similar problem, and protection mechanisms employed for those can be applied to the contract violation handler as well.
The thorniest issue was the interaction between a possibly-throwing contract violation handler and a noexcept
function: what should happen if a noexcept
function has a precondition, the program is compiled in a mode where preconditions are checked, the precondition is checked and fails, the contract violation handler is invoked, and it throws an exception? The possibility of “just allowing it” was considered but rejected, as it would be very problematic for noexcept
to mean “does not throw, unless the precondition fails” (code relying on the noexcept
would be operating on a possibly-incorrect assumption). The possibilities of not allowing contract violation handlers to throw, and of not allowing preconditions on noexcept
functions, were also considered but discarded as being too restrictive. The consensus in the end was, noexcept
functions can have preconditions, and contract violation handlers can throw, but if an exception is thrown from a contract violation handler while checking the preconditions of a noecept
function, the program will terminate. This is consistent with the more general rule that if an exception is thrown from a noexcept
function, the program terminates.
The question of whether a contract violation handler should be allowed to return, i.e. neither throw nor terminate but allow execution of the contract-violated function to proceed, came up, but there was no time for a full discussion on this topic.
When the Concepts TS was balloted by national standards bodies, some of the resulting ballot comments were deferred as design issues to be considered for the next revision of the TS (or its merger into the standard, whichever happens first). EWG looked at these issues at this meeting. Here’s the outcome for the most notable ones:
void foo(ConceptName c)
declares a constrained template function) was rejected on the basis that user feedback about this feature so far has been mostly positive.static_assert
or a constexpr_if
), not just in a requires-clause, was approved.{ expr } -> Same
).See also the section above where I talk about the bigger picture about Concepts and the possibility of the TS being merged into C++17.
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 already listed library features accepted into C++17 at this meeting (and at previous meetings) above.
The first revision of the Library Fundamentals TS was recently published and could be proposed for merger into C++17.
The second revision came into the meeting containing the following:
Комментировать | « Пред. запись — К дневнику — След. запись » | Страницы: [1] [Новые] |