Botond Ballo: Trip Report: C++ Standards Meeting in Jacksonville, February 2016 |
Project | What’s in it? | Status |
C++17 | Filesystem TS, Parallelism TS, Library Fundamentals TS I, if constexpr , and various other enhancements are in. Concepts, coroutines, and unified call syntax are out. Default comparisons and operator. to be decided at next meeting. |
On track for 2017 |
Filesystems TS | Standard filesystem interface | Published! Merging into C++17 |
Library Fundamentals TS I | optional , any , string_view and more |
Published! Merging into C++17 |
Library Fundamentals TS II | source code information capture and various utilities | Resolution of comments from national standards bodies in progress |
Concepts (“Lite”) TS | Constrained templates | Published! NOT merging into C++17 |
Parallelism TS I | Parallel versions of STL algorithms | Published! Merging into C++17 |
Parallelism TS II | TBD. Exploring task blocks, progress guarantees, SIMD. | Under active development |
Transactional Memory TS | Transaction support | Published! NOT merging into C++17 |
Concurrency TS I | future::then() , latches and barriers, atomic smart pointers |
Published! NOT merging into C++17 |
Concurrency TS II | TBD. Exploring executors, synchronic types, atomic views, concurrent data structures | Under active development |
Networking TS | Sockets library based on Boost.ASIO | Wording review of the spec in progress |
Ranges TS | Range-based algorithms and views | Wording review of the spec in progress |
Numerics TS | Various numerical facilities | Under active development |
Array Extensions TS | Stack arrays whose size is not known at compile time | Withdrawn; any future proposals will target a different vehicle |
Modules TS | A component system to supersede the textual header file inclusion model | Initial TS wording reflects Microsoft’s design; changes proposed by Clang implementers expected. Not targeting C++17.. |
Graphics TS | 2D drawing API | Wording review of the spec in progress |
Coroutines TS | Resumable functions | Initial TS wording will reflect Microsoft’s await design; changes proposed by others expected. Not targeting C++17. |
Reflection | Code introspection and (later) reification mechanisms | Design direction for introspection chosen; likely to target a future TS |
Contracts | Preconditions, postconditions, etc. | Unified proposal reviewed favourably. Not targeting C++17. |
Last week I attended a meeting of the ISO C++ Standards Committee in Jacksonville, Florida. This was the first committee meeting in 2016; you can find my reports on the 2015 meetings here (May 2015, Lenexa) and here (October 2015, Kona). These reports, particularly the Kona one, provide useful context for this post.
This meeting was pointedly focused on C++17. With the window for getting new features into C++17 rapidly closing, it was (and continues to be) crunch time for all the committee subgroups. Many important decisions about what will make C++17 and what won’t were made this week, as I’ll relate below.
Work continued on Technical Specifications (TS’s) as well. As a reminder, TS’s are a mechanism to publish specifications for features that are not quite ready for full standardization; they give implementers and users a chance to try out features while leaving the door open for breaking changes if necessary. Progress was made on both TS’s already in flight (like Networking and Ranges), and new TS’s started for features that didn’t make C++17 (like Coroutines and Modules).
Recall that, since C++11, the committee has been operating under a release train model, where a new revision of the C++ International Standard (IS) ships every 3 years. For any given revision, whatever features are ready when “the train leaves” are in, and whatever is not ready is out.
For C++17, the train is in the process of leaving. According to the intended schedule, the end of this meeting was the deadline for completing design review for new features, and the end of the next meeting (this June, in Oulu, Finland) will be the deadline for completing wording-level review for the same. This means that, coming out of this meeting, C++17 is essentially feature-complete (although reality is bit more nuanced than that, so read on).
The set of candidate features vying to make C++17 was very large – too large to complete them all and still ship C++17 on time. As a result, hard decisions had to be made about what is ready and what is not. I will describe these decisions and the deliberations that went into them below. My personal opinion is that, while C++17 may not contain everything everyone hoped it might, it will still be an important language revision with a respectable feature set.
So, let’s see what will be in C++17:
I’ve listed these in my Kona report – see the list of features in C++17 coming into Kona, and the listed of features voted into C++17 at Kona; I won’t repeat them here.
Technical Specifications that have been merged into C++17 at this meeting:
namespace std
(in the TS they were in std::experimental::parallel
), and overload with the existing standard algorithms.namespace std
(in the TS they were in std::experimental
).namespace std::filesystem
(in the TS they were in std::experimental::filesystem
).namespace std
(in the IS, since it was targeted at both C and C++, they were in the global namespace).Other features that have been voted into C++17 at this meeting:
[[fallthrough]]
attribute, indicating that one switch case intentionally falls through to the next[[nodiscard]]
attribute, indicating that the return value of a function should not be ignored[[maybe_unused]]
attribute, indicating that a variable may be intentionally unusedconstexpr
contexts&&
, ||
, and ,
(comma) operators, and passed in this form.begin
and end
iterator to have different types. This is necessary to accomodate the design of the Ranges TS, where a range is modelled as an (iterator, sentinel) pair rather than a pair of two iterators.*this
by valueenum
types. This underwent additional revisions since Kona to ensure that no existing code changes meaning, and that the intent of existing anguage constructs, such as explicit
, is preserved under the new rules.shared_from_this
not_fn
, cherry-picked into C++17 from the second Library Fundamentals TSconstexpr atomic::is_always_lock_free
constexpr std::hardware_{constructive,destructive}_interference_size
std::hypot
(option #2 from the paper)constexpr
modifiers to reverse_iterator
, move_iterator
, array
, and range accessstd::string
a non-const data()
member functionis_callable
, the missing INVOKE-related traitAs I mentioned above, the last chance to vote new features into C++17 will be at the next meeting, in Oulu. Here I list the features that are expected to come up for such a vote.
It’s important to note that, even after a feature receives design approval from the relevant working group (Evolution for language features, Library Evolution for library features), as all features listed here have, it doesn’t get into C++17 until it’s voted in at a plenary meeting, and sometimes that vote fails (this happened to some features at this meeting). So, while all these features are targeted at C++17, there are no guarantees.
The majority of these features passed design review, or re-review, at this meeting. For the language ones, I discuss them in more detail in the Evolution Working Group section below.
if constexpr
(formerly known as constexpr_if
, and before that, static_if
)template
is_contiguous_layout
(really a library feature, but it needs compiler support)joining_thread
, the name chosen for the proposed wrapper around std::thread
whose destructor joins the thread if it’s still running, rather than terminating the programmake_from_tuple()
(like apply()
, but for constructors)order<>
without defining std::less<>
swap()
accepts unequal allocatorsshared_ptr::weak_type
gcd()
std::iterator
, redundant members of std::allocator
, and is_literal
std::variant<>
was put forward for potential inclusion into C++17. As a large feature whose design was completed only recently, it faces a higher hurdle than the others, but there’s a chance it might make it.Of the language features listed above, default comparisons and operator dot are slightly controversial; we’ll have to see how they fare at the vote in Oulu.
Unified call syntax failed to gain consensus, due to concerns that it has the potential to make future code brittle. Specifically, it was pointed out that, since member functions are only considered for a call with non-member syntax if there are no non-member matches, calls with non-member syntax written to rely on this feature to resolve to member functions can break if a matching non-member function is added later, even if the added function is a worse match than the member function. The feature may come up for a vote again at the next meeting if new arguments addressing these concerns are made, but for now it is not going into C++17.
The Concepts Technical Specification (also called “Concepts Lite” to reflect that, unlike C++0x concepts, it includes only interface checking, not both interface and definition checking) was published in October 2015.
A proposal to merge the Concepts TS into C++17 was brought forward at this meeting, but it proved fairy controversial and failed to gain consensus. I was going to summarize the reasons why, but then I discovered fellow meeting attendee Tom Honermann’s excellent summary; I can’t possibly put it better or in more detail than he did, so I’ll just refer you to his post.
I’ll share a personal view on this topic: given how important a feature Concepts is for C++, I think’s it’s critical that we get it right, and thus I think the caution displayed in not merging into C++17 is appropriate. I also don’t view Concepts not merging into C++17 as “not having Concepts yet” or “having to wait another N years for Concepts”. We have Concepts, in the form of the Concepts TS. That’s published, and implemented (and is on track to be supported by multiple implementations in the near future), and I don’t see much reason not to use it, including in large production codebases. Yes, it being in a TS means that it can change in backward-incompatible ways, but I don’t expect such changes to be made lightly; to the extent that such changes are made, I would expect them to fall into the following categories:
Recapping the status of coroutines coming out of the last meeting:
await
proposal) already undergoing wording review, but with its ship vehicle (C++17 or a TS) uncertain.Since then, there have been two interesting developments:
await
proposal should target a TS, because of a lack of sufficient implementation and deployment experience, and because the design space for alternative approaches (such as the unified approach being sought) is still fairly open. To avoid these annotations being viral like await
, a mechanism for inferring the annotations within a TU is proposed; this is then extended to handle cross-TU calls by having the compiler generate two versions of a function (one for coroutine execution, and one for normal execution), and having the linker hook up cross-TU calls among these (the Transactional Memory TS uses a similar mechanism to deal with transaction-safe and transaction-unsafe versions of functions).
The “unified” aspect of this approach comes from the fact that a compiler can use a stackful implementation for part or all of a coroutine execution, without any change to the syntax. While this proposal is obviously still in an early design stage, I got the impression that this was the first time a “unified coroutines” proposal was sufficiently fleshed out to make the committee view it as a serious contender for being the C++ coroutines design.
In light of these developments, a discussion was held on whether the await
proposal should target a TS or C++17. The outcome was that a TS had a much stronger consensus, and this was the direction chosen. I would imagine that the unified proposal will then be pursued as a set of changes to this TS, or as a separate proposal in the same TS (or in a different TS).
In Kona, the committee decided that Modules would target a TS rather than C++17. I said in my Kona report that there’s a chance the committee might change its mind at this meeting, but that I thought it was unlikely. Indeed, the committee did not change its mind; a discussion of this proposal from the authors of the Clang modules implementation to make changes to the design being proposed by Microsoft, made it clear that, while significant convergence has occurred between the two implementations, there still remain gaps to be bridged, and targeting the feature for C++17 would be premature. As a result, Modules will continue to target a TS.
The Modules TS was officially created at this meeting, with its initial working draft consisting of Microsoft’s proposal. (The Clang implementers will formulate updated versions of their proposal as a set of changes to this draft.) The creation of an initial working draft is usually just a procedural detail, but in this case it may be significant, as the GCC and EDG implementers may view it as unblocking their own implementation efforts (as they now have some sort of spec to work with).
I summarize the technical discussion about Modules below.
Due to its relatively recent publication (and thus not yet having a lot of time to gain implementation and use experience), the Concurrency TS was not proposed for merging into C++17.
Some people expressed disappointment over this, because the TS contains the very popular future::then()
extension.
For similar reasons, the Transactional Memory TS was not proposed for merging into C++17.
Significant design progress has been made on contracts at this meeting. What started out as two very different competing proposals, had by the beginning of the meeting converged (#1, #2) to the point where the remaining differences were largely superficial. During the meeting, these remaining differences were bridged, resulting in a truly unified proposal (paper forthcoming). The proposal is very simple, leaving a lot of features as potential future extensions. However, it’s still too early in the process to realistically target C++17.
Reflection was never targeted for C++17, I just mention it because of its popularity. The Reflection Study Group did make significant progress at this meeting, as I describe below.
Having given an overview of the state of C++17, I will now give my usual “fly on the wall” account of the deliberations that went on in the Evolution Working Group (EWG), which reviews the design of proposed language features. I wish I could give a comparably detailed summary of goings-on in the other subgroups but, well, I can only be in one place at a time :)
EWG categorizes incoming proposals into three rough categories:
Accepted proposals:
The implementation status of Concepts also came up: Clang’s implementation is in progress, and MSVC and EDG both have it on their shortlist of features to implement in the near future; moreover, they have both indicated that Concepts not making it into C++17 will not affect their implementation plans.
*this
by value proposal was accepted as well. This version only proposes *this
as a new kind of thing that can appear in the capture list; that results in the lambda capturing the enclosing object by value, and this
inside the lambda referring to the copied object. (The previous version also proposed *
to mean a combination of =
and *this
, but people didn’t like that.) A couple of extension ideas were floated around: allowing moving *this
into the lambda, and capturing an arbitrary object to become the this
of the lambda; those are left for future exploration.constexpr_if
proposal. The proposal has undergone two syntax changes since the last meeting. The original proposed syntax was:constexpr_if (...) {
...
} constexpr_else constexpr_if (...) {
...
} constexpr_else {
...
}
constexpr if (...) {
...
} constexpr else constexpr if (...) {
...
} constexpr else {
...
}
if constexpr (...) {
...
} else if constexpr (...) {
...
} else {
...
}
return
statements contained in it do not contribute to return type deduction.friend
of the class just before the closing brace of the class declaration. Among other things, this allows libraries to leave unspecified whether their classes use explicit or implicit comparison operators, because users cannot tell the difference. The generation of an implicit operator is triggered the first time the operator is used without an explicit operator being in scope; a subsequent explicit declaration makes the program ill-formed.
A notable change since the last version of the proposal is that comparing a base object to a derived object is now ill-formed. To keep comparison consistent with copy construction and assignment, slicing during copy construction and assignment will also become ill-formed, unless the derived class doesn’t add any new non-static data members or non-empty bases. This is a breaking change, but the overwhelming majority of cases that would break are likely to be actual bugs, so EWG felt this was acceptable.
The semantics of <=
and >=
also came up: should a <= b
be implemented as a < b || a == b
or as !(a > b)
? EWG confirmed its previous consensus that it should be the former, but current standard library facilities such as std::tuple
use the latter. EWG felt that the library should change to become consistent with the language, while recognizing that it’s not realistic for this to happen before STL2 (the upcoming non-backwards-compatible overhaul of the STL). There was also some disagreement about the behaviour of wrapper types like std::optional
, which wrap exactly one underlying object; some felt strongly that for such type a <= b
should be implemented as neither of the above choices, but as a.wrapped_object <= b.wrapped_object
.
std::byte
type was proposed for the standard library, representing a byte of data without being treated as a character or integer type (the way char
flavours are). It’s defined as enum class byte : unsigned char {};
. EWG was asked to weigh in on extending C++’s aliasing rules to allow accessing the object representation of any object via a byte*
, the way that’s currently allowed via a char*
; this extension was approved. An alternative suggestion of allowing this for any scoped enumeration with a character type as its underlying type (as opposing to singling out std::byte
) was rejected.template
vector(Iter b, Iter e) -> vector>
auto
can be used instead of omitting the argument to trigger deduction for that argument only.std::vector v{myAlloc}; // uses std::allocator (oops)
std::vector v{myAlloc}; // allocator type deduced from 'myAlloc'
[[using ns: attr1, attr2, attr3]]
a shorthand for [[ns::attr1, ns::attr2, ns::attr3]]
. In an attribute specifier using this shorthand, all attribute names are looked up in the specified attribute namespace, without fallback to the global attribute namespace. If you want attributes from different namespaces on the same entity, you can either not use the shorthand, or use multiple specifiers as in [[using ns1: a, b, c]] [[using ns2: d, e]]
.is_contiguous_layout
type trait, which returns true for types for which every bit in the object representation participates in the value representation. Such a trait can be used to implement a higher-level is_uniquely_represented
trait, which is true if two objects of the type are equal if and only if their object representations are equal; this is in turn used for hashing. (The difference between the two traits is that is_uniquely_represented
can be specialized by the author of a class type, since the author gets to determine whether two objects with the same value representation are considered equal.) is_contiguous_layout
requires compiler support to implement, so it was brought in front of EWG, which approved it.template
, where V is a non-type template parameter whose type is deduced. In Kona it was discovered that this clashes a bit with Concepts, because the natural extension template
(which, given the relationship between auto
and concept names in other contexts, ought to mean a non-type template parameter whose type is deduced but must satisfy ConceptName
) already has a meaning in the Concepts TS (namely, a type parameter which must satisfy ConceptName
). The proposal author discussed this with with the editor of the Concepts TS, and decided this isn’t an issue: template
can retain its existing meaning in the Concepts TS, while “a non-type template parameter whose type is constrained by a concept” can be expressed a bit more verbosely as template requires ConceptName
. The feature is targeting C++17, time permitting.Proposals for which further work is encouraged:
for
loop exit strategies, which uses catch break
and catch default
to introduce the blocks that run after an early exit and after a normal exit, respectively. EWG liked the direction, but didn’t like the use of the catch
keyword, which is strongly associated with exceptions. More generally, there was a reluctance to reuse existing keywords (thus disqualifying the alternative of case break
and case default
). Other ideas such as context-sensitive keywords (allowing on break
and on default
, with on
being a context-sensitive keyword), and ugly keywords (like on_break
and on_default
) were proposed, but neither gained consensus. The proposal author said he would think offline about a better spelling.auto {x, y, z} = expr;
, which declares new names x
, y
, and z
, which bind to the “components” of the object expr
evaluates to. The notion of “components” is defined for three categories of types:
get(o)
which returns the N
th component of o
, for which the components are whatever these get
calls return. Notable examples are std::pair
and std::tuple
.get<>()
, that takes precedence.
Several notable points came up during this discussion:
auto __o = expr;
. Mandatory copy elision ensures that no actual copying is done. Alternatively, the user can use a reference syntax, such as auto& {x, y, z} = expr;
, resulting in the unnamed variable correspondingly having reference type, as in auto& __o = expr;
.x
, y
, and z
are not variables, they are just aliases to components of the unnamed object. The mental model here is to imagine that the compiler re-writes uses of x
to be uses of __o.field1
instead. (The alternative would be to make x
, y
, and z
references to the components of the unnamed object, but this wouldn’t support bit-field components, because you can’t have a reference to a bit-field.) I say “where possible”, because this can only be reasonably done for aggregates in categories (1) and (3) above.x
, y
, and z
are variables whose type is deduced as if declared with decltype(auto)
. (They can’t be aliases in this case, because there’s no knowing what get<>()
returns; for example, it could return an object constructed on the fly, so there would be nothing persistent to alias.)get<>()
they need to support something like tuple_size::value
. Some people also felt that using re-using get<>()
as the customization point is a mistake, and a new function meant specifically for use with this feature should be introduced instead.auto [x, y, z] = expr;
was proposed by some who argued that it looks more natural, because in a declaration context, having comma-separated things inside braces is unexpected.auto { X x, Y y, Z z } = expr;
, where X
, Y
, and Z
are type names (or, with the Concepts TS, concept names). This desire sort of clashes with the semantics of having x
, y
, and z
be aliases to the components, because we don’t have the freedom to give them types other than the types of the components. (One can imagine a different semantics, where x
, y
, and z
are copies of the components, where with explicit types we can ask for a components to be converted to some other type; the current semantics do not admit this sort of conversion.) However, it might still make sense to support explicit types and require that they match the types of the components exactly.The proposal authors intend to iterate on the proposal, taking the above feedback into account. It’s unlikely to make C++17.
short float
. EWG liked the direction. Some details remain to be worked out, such as the promotion rules (the proposal had short float
promote to float
, but it was pointed out that because of varags, they need to promote to double
instead), and accompanying standard library additions.std::optional
, except that it also allows storing a separate status object, whether or not a value object is present. This is useful for environments where exceptions cannot be used, or where immediately throwing an exception is undesirable for some other reason (for example, if we want an exception to be thrown in a delayed fashion, after a return value has made it to another thread or something and we actually try to access it). This was brought in front of EWG, because it’s an attempt to shape the future of error handling in C++. EWG liked the approach, and provided two specific pieces of guidance: first, the class should be marked [[nodiscard]]
, to indicate that it should not be ignored when used as a return value; and second, that the copyability/movability of the type should reflect that of the underlying value type.0o
, for octal literals. The existing prefix of just 0
makes it too easy to accidentally write an octal literal when you meant a decimal literal. The proposal author would like to eventually deprecate using just 0
as a prefix, though people pointed out this will be difficult due to the heavy use of octal literals in POSIX APIs (for example, for file permission modes).X::A*
to appear in a header without requiring a definition for X
to also appear in the header (forward-declarations of X
and X::A
will be sufficient). EWG found the use case compelling, because currently a lot of class definitions to appear in headers only because interfaces defined in the header use pointers or references to nested classes of the type. Several details still need to be worked out. (For example, what happens if a definition of X
does not appear in any other translation unit (TU)? What happens if a definition of X
appears in another TU, but does not define a nested class A
? What happens if it does define a nested class A
, but it’s private? The answer to some or all of these may have to be “ill-formed, no diagnostic required”, because diagnosing errors of this sort would require significant linker support.)Rejected proposals:
explicit
constructor has one parameter with a default argument. Such a constructor serves as both a converting constructor and a default constructor, and the explicit
applies to both, disqualifying the class from certain uses that require a non-explicit
default constructor. EWG felt that this is appropriate, and that if the class author intends for only the conversion constructor to be explicit
, they can write a separate default constructor instead of using a default argument.enum class
without qualification in a switch
statement was rejected, mostly because people felt that complicating C++’s name lookup rules in this way was not worth the win.void foo(int...);
would declare a template with a variadic number of int
parameters. The problem is, right now void foo(int...)
is accepted as an alternative spelling for void foo(int, ...)
which is a C-style varags function. This proposal would have disallowed the first spelling, leaving that syntax open for eventually denoting a variadic template. Notably, C already disallows the first spelling, which means this proposal would have improved compatibility with C; it also means any breakage would be limited to C++-only code using C-style varargs functions. Nonetheless, EWG members expressed concerns about code breakage, and the proposal didn’t gain consensus. It’s possible this may be revisited if the author comes back with data about the amount of real-world code breakage (or lack thereof) this would cause.0
or NULL
) should prefer to convert to std::nullptr_t
over void*
, failed to achieve consensus. The motivation was to support a proposed library change. Some people didn’t find this compelling enough, and felt we shouldn’t be catering to legacy uses of 0
and NULL
as null pointer constants.dynarray
class to wrap them, we want language syntax for what is really a smarter class type. Withdrawing the TS is just a procedural move that implies that any future proposals will target a different ship vehicle (a new TS, or the IS).[a..b)
, which would denote a range of values from a
up to (but not including) b
. The natural use case is integer ranges, although the syntax would have worked with any type that supported operator++
. The [a..b)
notation was inspired by the mathematical notation for half-open ranges, but implementers were strongly against this use of unbalanced brackets, pointing out that even if they didn’t make the grammar ambiguous strictly speaking, they would break tools’ ability to rely on bracket balancing for heuristics and performance. Alternative syntaxes were brought up, such as a..code>, but overall EWG felt that inventing a syntax for this is unnecessary, when a simple library interface (like range(a, b)
) would do. The proposal author was encouraged to work with Eric Niebler, editor of the Ranges TS, to collaborate on such a library facility.
for (auto val1 : range1; auto val2 : range2) { ... }
. Rejected because structured bindings in combination with a library facility for “zipping” ranges into a single range of tuple-like objects will allow this to be accomplished with syntax like for (auto {val1, val2} : zip(range1, range2))
. Concerns were raised about the ability of such a library facility to achieve the same performance as a first-class language feature could, but optimizer developers in the room said that this can be done.auto operator=(const A&) { ... }
, that is, an assignment operator whose return type is deduced using the auto
placeholder. Since the auto
placeholder always deduced a by-value return type, this is usually a bug (since assigment operators generally return by reference). EWG didn’t feel this was a problem worth solving.
EWG spent most of an entire day discussing Modules. The developers of Clang’s modules implementation described their experience deploying this implementation across large parts of Google’s codebase, with impressive results (for example, an average 40% reduction of compile times as a result of modularizing the most heavily used 10% of libraries). They then presented the most salient differences between their Modules design and Microsoft’s, formulated as a set of proposed changes to Microsoft’s design.
EWG discussed these proposed changes in depth. The following changes were reviewed favourably:
module { /* declarations here live in the global module */ }
is proposed. The main motivations are to allow tools to associate files with modules more easily (by not having to parse too far from the beginning of the file), and to avoid imposing a requirement that declarations in the global module must appear before everything else.module implementation ModuleName;
, to begin a module implementation unit (while module interface units use module ModuleName;
). The compiler already needs to know whether a translation unit is a module interface unit or a module implementation unit. It currently gets this information from metadata, such as compiler flags or the filename extension. This proposal places that information into the file contents.
The following changes did not yet gain a clear consensus in terms of direction. They will need to be iterated on and discussed further at future meetings:
import ModuleName;
to import
(or import "ModuleName"
or import to/ModuleName>
, or any other variation permitted by the #include
syntax), with the intention being that it would allow the compiler to find the module based only on its name (together with some per-translation implementation-defined metadata, such as the “#include search path” or an analogue), rather than requiring a separate mapping from module names to their locations. EWG found the motivation to be reasonable, but expressed caution about using strings in this context, and suggested instead using a hierarchical notation that can correspond to a filesystem path rather than being one, such as import x.y.z;
standing for the relative path x/y/z
(much as with Java imports).import
the module and #include
the side header. The Clang implementers argued that this was too heavy a burden for module authors and users, particularly in cases where a macro is added to a component’s interface, necessitating a change in how the component is imported. After a lengthy discussion, a basic consensus emerged that there was a lot of demand for both (1) a way to import a module that imported any macros exported by it, and (2) a way to import a module that did not import any macros, and that a Modules proposal would need to support both. The possibility of standardizing these as separate TS’s was brought up, but discarded because it would be confusing for users. No consensus was reached on which of (1) or (2) would be the default (that is, which would simply writing import ModuleName;
do), nor on what semantics (2) might have if the module does in fact export macros (the options were to given an error at the import site, and to import the module anyways, silently stripping macros from the set of imported entities).import header "header.h";
), which would cause the module to export all macros defined at the end of the header. The motivation for this is that, when transitioning a large codebase to use modules in some order other than strictly bottom-up, a contents of a legacy header can be brought in both through a direct #include
, and via a module. Direct inclusion relies, as ever, on an include guard to determine whether the file has been previously included. An inclusion via a module must, therefore, cause that include guard to become defined, to avoid a subsequent direct inclusion bringing in a second copy of the declared entities. The Clang implementers originally tried having this mechanism export just the header guard, but that requires heuristically detecting which macro is the header guard; this can be done in most cases, but is practically impossible for certain headers, such as standard C library headers, which have more complicated inclusion semantics than simple include guards. Another alternative that was tried was allowing multiple inclusion, and performing equivalence merging (a deep structural comparison of two entities) to weed out duplicate definitions, but this was found to be slow (undoing much of the compile-time performance benefit that Modules bring) and error-prone (slight differences in inclusion contexts could lead to two instances of a definition being just different enough not to be merged).
EWG has a pretty good track record of getting through most if not all of the proposals on its plate in a given meeting, but at this meeting, due to the amount of time spent discussing Concepts, Coroutines, and Modules, there were 17 papers it did not get a chance to look at. I won’t list them all (see the list of papers on the committee’s website if you’re interested), but I’ll call out three that I was particularly excited about and would have liked to see presented:
get(t)
, tuple_size::value
, and tuple_element::type
, to be used on structures whose data members are all public (roughly; the exact conditions are spelled out in the paper). I was particularly excited about this, because it would have unlocked a simple form of reflection (iteration over members) for such structures. However, the proposal probably would have encountered opposition for the same reason
Комментировать | « Пред. запись — К дневнику — След. запись » | Страницы: [1] [Новые] |