Document number: | J16/99-0025 = WG21 N1201 |
Date: | 26 April 1999 |
Project: | Programming Language C++ |
Reply to: | Daveed Vandevoorde |
daveed@vandevoorde.com |
Also see Table of Contents - Open Issues, Table of Contents - Closed Issues, Index by Section Number - Open Issues and Index by Section Number - Closed Issues
The purpose of this document is to serve as the committee's memory for Core Working Group issues.
This document is in an experimental format designed for both viewing via a world-wide web browser and hard-copy printing. The format is taken from that used in N1163, the Library WG Issues List.
The issues list related HTML files can be placed in the same disk directory as the IS HTML files also available from the committee web site. This enables web browsers to link to directly from issues to related IS sections.
It is the policy of the committee to accept any issue from a committee member which is well-formed, specific, and understandable, as determined by the issues list maintainer. The issues list maintainer may edit an issue for brevity, grammar, or form.
Comments on the current state of discussions are often given at the end of issues (particularly open issues) in an italic font. Such comments are for information only and should not be given undue importance.
Excepts from reflector discussions are prefaced by the underlined message author's name.
Editorial comments on the issue itself supplied by the issue list maintainer appear in square brackets.
Issues on this list should not to be confused with Defect Reports (DR's).
While some of the issues on this issues list will eventually be elevated
to Defect Reports, other issues will be closed without action. Defect
Reports in turn may become the basis for Technical Corrigenda (TC's), or
may be closed without action other than a Record of Response (RR).
Issue status
The status categories are still evolving. In the current revision the following categories are used:
Open - The CWG has discussed the issue but is not yet ready to move the issue forward. There are several possible reasons for open status:
Drafting - Informal consensus has been reached and is described in rough terms in a Tentative Resolution, but the CWG awaits drafting of an exact Proposed Resolution wording for review.
Review - Exact wording of a Proposed Resolution is now available for review on an issue for which the CWG previously reached informal consensus.
Ready - The CWG has reached consensus that the issue is a defect in the Standard, the Proposed Resolution is correct, and the issue is ready to forward to the full committee for further action as a proposed defect report.
Closed - The full committee has approved the item as a proposed defect report.
Duplicate - The defect is identical to or a subset of another issue.
NAD - The CWG has reached consensus that the issue is not a defect in the Standard, and the issue is ready to forward to the full committee as a proposed record of response. A Rationale discusses the CWG's reasoning.
Extension - The CWG has reached consensus that the issue is not a defect in the Standard, but agrees that the problem described is sufficiently important that a language extension might be considered. The record of response for this issue will indicate that it is not a defect. The CWG is not actively considering extensions at this time; the issue remains open for future use in the event that extensions are considered.
In 3.2/4 bullet 4, it's presumably the case that a conversion to T* requires that T be complete only if the conversion is from a different type. One could argue that there is no conversion (and therefore the text is accurate as it stands) if a cast does not change the type of the expression, but it's probably better to be more explicit here.
On the other hand, this text is non-normative (it's in a note).
Response of Core@Dublin'99
A close and careful reading of 5.2.9/2 already concludes to this for static_casts (while it is not true for dynamic_cast 5.2.7).
From reflector message core-7938
The wording in basic.def.odr paragraph 2 about "potentially evaluated" is incomplete. It does not distinguish between expressions which are used as "integral constant expressions" and those which are not; nor does it distinguish between uses in which an objects address is taken and those in which it is not. (A suitable definition of "address taken" could be written without actually saying "address".)
Currently the definition of "use" has two parts (part (a) and (d) below); but in practice there are two more kinds of "use" as in (b) and (c):
I don't think we discussed (c).
The CWG at Dublin '99 concluded that the substantive part of this defect is convered in issue 48.
From reflector message core-7848
Consider this code:
If we had written
A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.But in the original code, we don't have an unqualified "next" that refers to anything but the current scope. I think the intent was to allow the code, but I don't find the wording clear on on that point.
Is there another section that makes it clear whether the original code is valid? Or am I being obtuse? Or should the quoted section say "An unqualified name N used in a class ..."?
The CWG at Dublin '99 agreed that it is sufficiently clear that "name" includes qualified names and hence the usual lookup rules make this legal. The issue need not be a defect.
From reflector message core-7838
Footnotes 26 and 29 both use the phrase "following the function declarator" incorrectly: the function declarator includes the parameter list, but the footnotes make clear that they intend what's said to apply to names inside the parameter list. Presumably the phrase should be "following the function declarator-id."
Resolution: (Dublin '99)
Change text in [basic.lookup.unqual ] 3.4.1/6 from:A name used in the definition of a function [footnote: This refers to unqualified names following the function declarator; such a name may be used as a type or as a default argument name in the parameter-declaration-clause, or may be used in the function body. end footnote] that is ...to:
A name used in the definition of a function following the function's declarator-id[footnote: This refers to unqualified names that occur, for instance, in a type or default argument expression in the parameter-declaration-clause or used in the function body. end footnote] that is ...Change text in [basic.lookup.unqual ] 3.4.1/8 from:
A name used in the definition of a function that is a member function (9.3) [footnote: That is, an unqualified name following the function declarator; such a name may be used as a type or as a default argument name in the parameter-declaration-clause, or may be used in the function body, or, if the function is a constructor, may be used in the expression of a mem-initializer. end footnote] of class X shall be ...to:
A name used in the definition of a member function (9.3) of class X following the function's declarator-id [footnote: That is, an unqualified name that occurs, for instance, in a type or default argument expression in the parameter-declaration-clause, in the function body, or in an expression of a mem-initializer in a constructor definition. end footnote] shall be ...
(Previously numbered 915.)
Given the following test case:
Second, it appears the WP is silent as to what happens with the call `f(e1)': do the different default arguments create an ambiguity? is the local choice preferred? or the global? In Santa Cruz, the CWG agreed to the following tentative resolution:
Tentative Resolution (Santa Cruz '98)
In basic.lookup.koenig paragraph 2, change
If the ordinary unqualified lookup of the name finds the declaration of a class member function, the associated namespaces and classes are not considered.to
If the ordinary unqualified lookup of the name finds the declaration of a class member function or the declaration of a function at block scope, the associated namespaces and classes are not considered.
However, in Dublin the CWG decided to treat this issue as a subset of Issue 1 instead. In part this was motivated by Mike Ball's observation that the behavior proposed would also apply to local using-declarations (which may not be desirable).
From reflector message core-7768
If an argument used for lookup is the address of a group of overloaded functions, are there any associated namespaces or classes? What if it's the address of a function template?
My inclination is to say no to both.
From Mike Miller:
We discussed this on the reflector a few weeks ago. I'll leave the template case for the Core III experts, but I'd find it surprising if the overload case weren't handled as the obvious generalization of the single-function case. For a single function, the associated namespaces are those of the types used in the parameters and return type; I would expect that using an overloaded function name would simply be the union of the namespaces from the members of the overload set. That would be the simplest and most intuitive, IMHO -- is there an argument for doing it differently?
Resolution: (Dublin, '99)
In [basic.lookup.koenig ] 3.4.2/2, add following the last bullet in the list of associated classes and namespaces for various argument types (not a bullet itself because overload sets and templates do not have a type):
In addition, if the argument is the name or address of a set of overloaded functions and/or function templates, its associated classes and namespaces are the union of those associated with each of the members of the set: the namespace in which the function or function templates is defined and the classes and namespaces associated with its (non-dependent) parameter types and return type.
>From reflector message core-7952.
Section basic.lookup.koenig includes the following:
Tentative Resolution (Dublin '99)
A majority of the CWG agreed to add the enclosing class of a nested class type to the Koenig set of that type. Clark Nelson volunteered to draft words.
>From reflector message core-7954.
When a union is used in argument-dependent lookup, the union's type is not an associated class type. Consequently, code like this will fail to work.
Also, this section is written as if unions were distinct from classes. So adding unions to the "associated classes" requires either rewriting the section so that "associated classes" can include unions, or changing the term to be more inclusive, e.g. "associated classes and unions" or "associated types".
Jason Merrill: Perhaps in both cases, the standard text was intended to only apply to anonymous unions.
In Dublin, Liam Fitzpatrick pointed out that one cannot create expressions of an anonymous union type.
The CWG in Dublin concluded that a close and careful reading of the standard does in fact indicate that unions are included in "class-types" in this case. Hence, this should not be treated as a defect.
From reflector message core-7686
The C++ standard has inherited the definition of the 'exit' function more or less unchanged from ISO C.
However, when the 'exit' function is called, objects of static extent which have been initialised, will be destructed if their types posses a destructor.
In addition, the C++ standard has inherited the definition of the 'signal' function and its handlers from ISO C, also pretty much unchanged.
The C standard says that the only standard library functions that may be called while a signal handler is executing, are the functions 'abort', 'signal' and 'exit'.
This introduces a bit of a nasty turn, as it is not at all unusual for the destruction of static objects to have fairly complex destruction semantics, often associated with resource release. These quite commonly involve apparently simple actions such as calling 'fclose' for a FILE handle.
Having observed some very strange behaviour in a program recently which in handling a SIGTERM signal, called the 'exit' function as indicated by the C standard.
But unknown to the programmer, a library static object performed some complicated resource deallocation activities, and the program crashed.
The C++ standard says nothing about the interaction between signals, exit and static objects. My observations, was that in effect, because the destructor called a standard library function other than 'abort', 'exit' or 'signal', while transitively in the execution context of the signal handler, it was in fact non-compliant, and the behaviour was undefined anyway.
This is I believe a plausible judgement, but given the prevalence of this common programming technique, it seems to me that we need to say something a lot more positive about this interaction.
Curiously enough, the C standard fails to say anything about the analogous interaction with functions registered with 'atexit' ;-)
(Also see reflector messages 7687 7688 7689 7691)
Tentative Resolution:
The current Committee Draft of the next version of the ISO C standard specifies that the only standard library function that may be called while a signal handler is executing is 'abort'. This would solve the above problem.
[This issue should remain open until it has been decided that the next
version of the C++ standard will use the next version of the C standard
as the basis for the behavior of 'signal'.]
From N1169, "Proposed Defect Reports on ISO/IEC 14882, Programming
Lanugages - C++".
A reference is rebindable. This is surprising and unnatural. This can also cause subtle optimizer bugs.
Example:
Proposal: make T& equivalent to T* const by extending the scope of basic.life paragraph 9 to references.
Proposed Resolution (Mike Miller)
Section basic.life paragraph 9 makes the construction of a new object in the same location undefined behavior if the object was const and either static or automatic, presumably to allow optimizers to rely on the known value of such an object. However, nothing is said about an object with a member of reference type.
Analysis
When this issue was discussed in Santa Cruz, there was general agreement in the core group that something should be done to make it undefined behavior to "rebind" a reference member through reconstruction of its containing object. The issue suggests amending basic.life paragraph 9 to cover the reference case as well as the const case.
The proposal below, however, takes a different approach. The current basic.life paragraph 9 seems more intended to address the "ROM-ability" of an object than optimizer considerations. For one thing, its applicability is limited only to static and automatic objects, which are more susceptible to the kind of analysis required to determine if an object can be placed into read-only memory than are objects that are dynamically allocated in free store and whose lifetime is less easily determined. Furthermore, the restriction is not upon use of the value of such an object after reallocation, which is where an optimizer would be expected to encounter trouble; instead, it is the mere act of reallocation itself that produces undefined behavior (just like any other attempt to modify a const object, per dcl.type.cv paragraph 4).
basic.life paragraph 7 lists restrictions on using a pointer, reference, or name that previously referred to an object to refer to a new object created in the same storage. Since the concern here is optimization, in particular assumptions about the binding of a reference member whose previous binding was known, it seems more natural to augment the restrictions of basic.life paragraph 7 to address the issue of reference members (i.e., placing a limitation on the use of the new object in confusing ways rather than on its creation). In addition, this paragraph is not limited to static and automatic objects, and there seems to be no reason to allow "rebinding" of references in free-store objects, either.
Proposed Resolution
Add a new bullet to the list of restrictions in basic.life paragraph 7, following the second bullet ("the new object is of the same type..."):
>From reflector message core-7956.
The text of basic.life paragraph 2 currently reads,
The phrase "an object of type" is obviously incorrect. I believe it should read "an object of POD type." Does anyone disgree?
The CWG at Dublin '99 agreed.
From reflector message core-7850
Can you use memcpy on non-member POD subobjects of non-POD objects?
In 3.9/2,3 [basic.types] we have:
For any complete POD object type T, whether or not the object holds a valid value of type T, the underlying bytes (intro.memory) making up the object can be copied into an array of char or unsigned holds a valid value of type T, the underlying bytes (intro.memory) making up the object can be copied into an array of char or unsigned char.* If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value. [Example elided]Paragraph 3 doesn't repeat the restriction of paragraph 2. Should it be assumed? Otherwise only complete POD types are copyable to an array of char and back, but scribbling over subobjects is OK. (Or perhaps a "distinct T object" is a complete object...)*[Footnote: By using, for example, the library functions (lib.headers) memcpy or memmove. --- end footnote]For any POD type T, if two pointers to T point to distinct T objects obj1 and obj2, if the value of obj1 is copied into obj2, using the memcpy library function, obj2 shall subsequently hold the same value as obj1.
Resolution: (Dublin '99)
Change text in [basic.types ] 3.9/2 from:For any complete POD object type T, ...to:
For any object (other than a base class subobject) of POD type T, ...Change text in [basic.types ] 3.9/3 from:
For any POD type T, if two pointers to T point to distinct T objects obj1 and obj2,to:
For any POD type T, if two pointers to T point to distinct T objects obj1 and obj2,
where neither obj1 nor obj2 is a base class subobject, ...
From reflector message core-7865
An operator expression can, according to
expr
paragraph 2, require transformation into function call syntax. The
reference in that paragraph is to
over.oper
, but it should be to
over.match.oper
.
This appears not to be a problem because the sub-sections 13.5.1, 13.5.2, ... of the referenced section are in fact relevant.
5.2.5/4 should make it clear that when a nonstatic member is referenced in a member selection operation, the type of the left operand is implicitly cast to the naming class of the member. This allows for the detection of access and ambiguity errors on that implicit cast.
The CWG in Dublin decided that a non-normative note in 11.2/4 already indicates this. Hence, the relevant part of that note should be made normative---Tom Wilcox will draft the words.
Section 5.2.9 paragraph 6 should make it clear that when any of the "inverse of any standard conversion sequence" static_casts are done, the operand undergoes the lvalue-to-rvalue conversions first.
The CWG at Dublin '99 agreed and Clark Nelson volunteered for drafting.
Is it okay to use a static_cast to cast from a private base class to a derived class? That depends on what the words "valid standard conversion" in paragraph 8 mean -- do they mean the conversion exists, or that it would not get an error if it were done? I think the former was intended -- and therefore a static_cast from a private base to a derived class would be allowed.
The CWG at Dublin '99 concluded that static_cast from a private class to a derived class is not allowed outside a member from the derived class, because 4.10/3 implies that the conversion is not valid. (Classic style casts work.)
From reflector message core-7761
Section 12.5/4 [class.free] says:
If a delete-expression begins with a unary :: operator, the dealloca- tion function's name is looked up in global scope. Otherwise, if the delete-expression is used to deallocate a class object whose static type has a virtual destructor, the deallocation function is the one found by the lookup in the definition of the dynamic type's virtual destructor (_class.dtor_).2) Otherwise, if the delete-expression is used to deallocate an object of class T or array thereof, the static and dynamic types of the object shall be identical and the dealloca- tion function's name is looked up in the scope of T. If this lookup fails to find the name, the name is looked up in the global scope. If the result of the lookup is ambiguous or inaccessible, or if the lookup selects a placement deallocation function, the program is ill- formed.I contrast that with 5.3.4/16,17 [expr.new] :
If the new-expression creates an object or an array of objects of class type, access and ambiguity control are done for the allocation function, the deallocation function (_class.free_), and the construc- tor (_class.ctor_). If the new expression creates an array of objects of class type, access and ambiguity control are done for the destruc- tor (_class.dtor_).I think nothing in the latter paragraphs implies that the deallocation function found is the same as that for a corresponding delete-expression. I suspect that may not have been intended and that the lookup should occur "as if for a delete-expression".If any part of the object initialization described above19) terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression. If no unambiguous matching deallocation function can be found, propagating the exception does not cause the object's memory to be freed. [Note: This is appro- priate when the called allocation function does not allocate memory; otherwise, it is likely to result in a memory leak. ]
Rationale:
Paragraphs 16 through 18 are sufficiently correct and unambiguous as
written.
From reflector message core-7911
expr.new paragraph 6 says:
The expression in a direct-new-declarator shall have integral type (basic.fundamental ) with a non-negative value.I assume the intent was to also allow enumeral types, as we do in expr.sub ?
Proposed Resolution (Dublin '99)
Replace "integral type" by "enumeration or integral type" in expr.new paragraph 6.
An expression of the form pointer + enum (see paragraph 5) is not given meaning, and ought to be, given that paragraph 2 of this section makes it valid. Presumably, the enum value should be converted to an integral value, and the rest of the processing done on that basis. Perhaps we want to invoke the integral promotions here.
[Should this apply to (pointer - enum) too?]
The CWG at Dublin '99 concluded that this is not a defect because paragraph 1 enables "the usual arithmetic conversions".
From reflector messages core-7890, 7895, 7896, 7904
Nathan Myers: In expr.eq , we have :
Pointers to objects or functions of the same type (after pointer conversions) can be compared for equality. Two pointers of the same type compare equal if and only if they are both null, both point to the same object or function, or both point one past the end of the same array.What does this say, when we have
Mike Miller: I think this is reading more into the statement in expr.eq paragraph 1 than is actually there. What does it mean for a pointer to "point to" an object? I can't find anything that definitively says that i+1 cannot "point to" j[0] (although it's obviously not required to do so). If i+1 is allowed to "point to" j[0], then i+1==j is allowed to be true, and there's no defect. There are places where aliasing is forbidden, but the N+1th element of an array doesn't appear to be one of them.
To put it another way, "points to" is undefined in the Standard. The only definition I can think of that encompasses the possible ways in which a pointer can get its value (e.g., the implementation-defined conversion of an arbitrary integer value to a pointer) is that it means "having the same value representation as would be produced by applying the (builtin) & operator to an lvalue expression designating that object". In other words, if the bits are right, it doesn't matter how you produced the value, as long as you didn't perform any operations that have undefined results. The expression i+1 is not undefined, so if the bits of i+1 are the same as those of &j[0], then i+1 "points to" j[0] and i+i==j is allowed to be true.
Tom MacDonald: C9X contains the following words for the "==" operator:
Two pointers compare equal if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to on past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.Matt Austern: I don't think there's anything wrong with saying that the result of
What Nathan has pointed out is that, according to one interepretation of the C++ standard, the result of that fragment is precisely specified. That's probably not what we intended.
As I see it, the questions are:
Mike Miller: A similar question could be raised about different objects that (sequentially) share the same storage. Consider the following:
The CWG at Dublin '99 agreed on the intent (not to force the presence or absence of spacing storage), but coming up with the correct words is tricky. In particular, the C9X wording does not seem satisfactory. Clark Nelson pointed out that intro.memory
may be a good place to start with the drafting task. He and Mike Miller volunteered to come with words.
From reflector messages core-7960, 7961, 7962 and 7965.
Bjarne Stroustrup: I think that once you have said S::, c is in scope so that
Mike Miller: I'd like to think that's what it meant, but I don't believe that's what it said. According to basic.scope paragraph 1, the scope of a name is the region "in which that name may be used as an unqualified name." You can, indeed, use a qualified name to refer to a name that is not in scope, but that only goes to reinforce my point that "S::c" is not in scope at the point where the expression containing it is used. I think the phrase "within its scope" is at best misleading and should be removed. (Unless there's a reason I'm missing for restricting the use of static member constants to their scope.)
As far as I can tell from expr.const paragraph 2, "arithmetic constant expressions" (as distinct from "integral constant expressions") are used only in static initializers to distinguish between static and dynamic initialization. They include floating point types and exclude non-type template parameters, as well as the const variables and static data members.
I'm guessing that should be "non-static member," like the similar prohibition in class.cdtor regarding out-of-lifetime access to members of non-POD class objects.
Tentative Resolutions (Dublin '99)
>From reflector message core-7982.
Consider:
From conv.ptr paragraph 1: "A null pointer constant is an integral constant expression rvalue of integer type that evaluates to zero."
From expr.const paragraph 1: "An integral constant-expression can involve only literals, enumerators, const variables or static members of integral or enumeration types initialized with constant expressions, ..."
In lex.icon : No mention of true or false as an integer literal.
From lex.bool : true and false are Boolean literals.
So the definition of q is certainly valid, but the validity of p depends on how the sentence in expr.const is parsed. Does it mean
If the latter, then (3.0 < 4.0) is a constant expression, which I don't think we ever wanted. If the former, though, we have the anomalous notion that true and false are not constant expressions.
Now, you may argue that you shouldn't be allowed to convert false to a pointer. But what about this?
I think that it should be, and that failure to make it so was just an oversight.
The CWG at Dublin '99 concluded this is not a defect. expr.const reveals that all types of literals can appear in integral constant expressions, but floating-point literals must immediately be cast to an integral type.
I cannot find anything in the standard that tells me the meaning of a storage-class-specifier on a function template declaration. In particular, there is no indication what effect, if any, it has on the storage class of the instantiations.
There is an explicit prohibition of storage-class-specifiers on explicit specializations.
For example, if we have
template<class T> static int foo(T) { return sizeof(T); }does this generate static functions for all instantiations? By 7.1.1 the storage class applies to the name declared in the declarator, which is the template foo, not an instantiation of foo, which is named with a template-id. There is a statement in clause 14 that template names have linkage, which supports the contention that "static" applies to the template, not to instantiations.
So what does the specifier mean? Lacking a direct statement in the standard, I see the following posibilities, in my preference order.
From John Spicer
The standard does say that a namespace scope template has external linkage unless it is a function template declared "static". It doesn't explicitly say that the linkage of the template is also the linkage of the instantiations, but I believe that is the intent. For example, a storage class is prohibited on an explicit specialization to ensure that a specialization cannot be given a different storage class than the template on which it is based.
Mike: This makes sense, but I couldn't find much support in the document. Sounds like yet another interpretation to add to the list.The standard does not talk about the linkage of instantiations, because only "names" are considered to have linkage, and instances are not really names. So, from an implementation point of view, instances have linkage, but from a language point of view, only the template from which the instances are generated has linkage.John: Agreed.
Mike: Which is why I think it would be cleaner to eliminate storage class specifiers entirely and rely on the unnamed namespace. There is a statement that specializations go into the namespace of the template. No big deal, it's not something it says, so we live with what's there."export" is an additional attribute that is separate from linkage, but that can only be applied to templates with external linkage.John: That would mean prohibiting static function templates. I doubt those are common, but I don't really see much motivation for getting rid of them at this point.
Mike: I can't find that restriction in the standard, though there is one that templates in an unnamed namespace can't be exported. I'm pretty sure that we intended it, though.John: I can't find it either. The "inline" case seems to be addressed, but not static. Surely this is an error as, by definition, a static template can't be used from elsewhere.
The CWG at Dublin '99 noted that 7.1.1/4 already seems to imply that "static" is not allowed on templates. However, other places suggest otherwise. The CWG concluded that it should be clarified as not legal; Daveed Vandevoorde is to draft words.
Can a typedef redeclaration be done within a class?
The CWG at Dublin '99 resolved to make this illegal by replacing "In a given scope" in [dcl.typedef] 7.1.3/2 by "In a given non-class scope". (This removes the contradiction with 9.2/1.)
The following code does not compile with the EDG compiler:
A variable of const-qualified integral or enumeration type initialized by an integral constant expression can be used in integral constant expressions.This doesn't say it can't be const volatile-qualified, although I think that was what was intended.
Tentative Resolution:
Change to dcl.type.cv
A variable of non-volatile const-qualified ...
I can't find the answer to the following in the standard. Does anybody have a reference?
The syntax for elaborated type specifier is
An elaborated-type-specifier shall be used in a friend declaration for a class.*And in 14.5.3 we find the example[Footnote: The class-key of the elaborated-type-specifier is required. --- end footnote]
[Example:
The CWG at Dublin '99 agrees this is a bug, and that (among others) 7.1.5.3 should be updated (perhaps using the grammatical construct class-name). Jamie Schmeiser volunteered to draft the exact changes.
>From reflector messages core-7966 through 7974.
A change was introduced into the language that made names first declared in friend declarations "invisible" to normal lookups until such time that the identifier was declared using a non-friend declaration. This is described in 7.3.1.2p3 and 11.4p9 (and perhaps other places).
The standard gives examples of how this all works with friend declarations, but there are some cases with nonfriend elaborated type specifiers for which there are no examples, and which might yield surprising results.
The problem is that an elaborated type specifier is sometimes a declaration and sometimes a reference. The meaning of the following code changes depending on whether or not friend class names are injected (visibly) into the enclosing namespace scope.
Mike Miller: Yes.
John Spicer: Second, is this the desired behavior, or should all elaborated type specifiers (and not just those of the form "class-key identifier;") have the effect of finding previously declared "invisible" names and making them visible?
Mike Miller: That's not how I would categorize the effect of "struct B;". That declaration introduces the name "B" into namespace N in exactly the same fashion as if the friend declaration did not exist. The preceding friend declaration simply stated that, if a class N::B were ever defined, it would have friendly access to the members of N::X. In other words, the lookups in both "struct A*..." and "struct B;" ignore the friend declarations.
(The standard is schizophrenic on the issue of whether such friend declarations introduce names into the enclosing namespace. 3.3p4 says,
John Spicer: The previous declaration of B is not completely ignored though, because certainly changing "friend struct B;" to "friend union B;" would result in an error when B was later redeclared as a struct, wouldn't it?
Bill Gibbons: Right. I think the intent was to model this after the existing rule for local declarations of functions (which dates back to C), where the declaration is introduced into the enclosing scope but the name is not. Getting this right requires being somewhat more rigorous about things like the ODR because there may be declaration clashes even when there are no name clashes. I suspect that the standard gets this right in most places but I would expect there to be a few that are still wrong, in addition to the one Mike pointed out.
Mike Miller: Regarding would result in an error when B was later redeclared
I don't see any reason why it should. The restriction that the class-key must agree is found in 7.1.5.3 and is predicated on having found a matching declaration in a lookup according to 3.4.4. Since a lookup of a name declared only (up to that point) in a friend declaration does not find that name (regardless of whether you subscribe to the "does-not-introduce" or "introduces-invisibly" school of thought), there can't possibly be a mismatch. (BTW, I couldn't find anything in the Standard that forbids _defining_ a class with a mismatched class-key, only using one in an elaborated-type-specifier. Is this a hole that needs to be filled?)
John Spicer: This is what 7.1.5.3 paragraph 4 says:
Mike Miller: Regarding I think the intent was to model this after the existing rule for local declarations of functions (which dates back to C)
Actually, that's not the C (1989) rule. To quote the Rationale from X3.159-1989:
Yes, I think if this is to be made illegal, it would have to be done with the ODR; the name-lookup-based current rules clearly (IMHO) don't apply. (Although to be fair, the [non-normative] note in 3.3p4 sounds as if it expects friend invisible injection to trigger the multiple-declaration provisions of that paragraph; it's just that there's no normative text implementing that expectation.)
To conclude my comments on this topic, I'll just mention that I don't necessarily think that the Standard's broken here. There is no requirement that a class declared in a friend declaration ever be defined. Explicitly putting an incompatible declaration into the namespace where that friend class would have been defined is, to me, just making it impossible to define -- which is no problem, since it didn't have to be defined anyway. The only error would occur if the same-named but unbefriended class attempted to use the nonexisting grant of friendship, which would result in an access violation.
Regarding [7.1.5.3] could be interpretted to say that ... are both invalid.
I see -- according to this interpretation, an elaborated-type-specifier that disagreed with the definition of the class would be wrong, regardless of whether it preceded or followed the class definition, and the class definition would be right even if it followed a contrary elaborated- type-specifier. I suppose that's plausible. Thanks.
Bill Gibbons: Nor does the ODR currently disallow:
But the obvious form of the missing rule (all declarations of a class within a program must have compatible struct/class/union keys) would also answer the original question.
The declarations need not be visible. For example:
(Previously numbered 914.)
The CWG at Dublin '99 decided that any semantics associated with the typename keyword in using-declarations should be considered an extension.
Issue 1:
The working paper is not clear about how the typename/template keywords interact with using-declarations:
The core WG already resolved this issue according to (1), but the wording does not seem to have been added to the standard. New wording needs to be drafted.
Issue 2:
Either way, one more point needs clarification. If the first option is adopted:
From John Spicer:
The "not a new declaration" decision is more of a guiding principle than a hard and fast rule. For example, a name introduced in a using-declaration can have different access than the original declaration.Tentative Resolution:Like symbolic links, a using-declaration can be viewed as a declaration that declares an alias to another name, much like a typedef.
In my opinion, "X c;" is already well-formed. Why would we permit typename to be used in a using-declaration if not to permit this precise usage?
In my opinion, all that needs to be done is to clarify that the "typeness" or "templateness" attribute of the name referenced in the using-declaration is attached to the alias created by the using-declaration. This is solution #1.
The rules for multiple declarations with the same name in the same scope
should treat a using-declaration which names a type as a typedef,
just as a typedef of a class name is treated as a class declaration. This
needs drafting work. Also see issue 36.
From reflector message core-7811
Section 7.3.3 [namespace.udecl] paragraph 8 says:
A using-declaration is a declaration and can therefore be used repeatedly where (and only where) multiple declarations are allowed.It contains the following example:
Indeed, if the double using-declaration for A::i is prohibited in f, why should it be allowed in namespace A1?
Proposed Resolution: (Dublin '99)
Change the comment "See also
Core issue 56
and
Core issue 85
.
>From reflector message core-7994: Consider the following:
If a function declaration in namespace scope or block scope has the same name and the same parameter types as a function introduced by a using-declaration, the program is ill-formed.Based on the context ( namespace.udecl paragraph 10 simply reiterates the requirements of basic.scope ), one might wonder if the failure to exempt extern "C" functions was intentional or an oversight. After all, there is only one function f() involved, because it's extern "C", so ambiguity is not a reason to prohibit the using-declaration.
This also breaks the relatively strong parallel between extern "C" functions and typedefs established in our discussion of Core issue 14 in Santa Cruz. There the question was for using-directives:
In the context of using-declarations, there is no explicit extension of the restrictions in basic.scope paragraph 4 except as noted above for function declarations; thus the parallel scenario for a typedef is not ill-formed:
I think namespace.udecl paragraph 11 ought to be rewritten as:
If a function declaration in namespace scope or block scope has the same name and the same parameter types as a function introduced by a using-declaration, and the declarations do not declare the same function, the program is ill-formed.
Martin O'Riordan: (core-7995) Agreed.
However, I have noticed several places where we have discrepancies between what is said (primarily) in basic and what is said in dcl.dcl . My suspicion is that when we significantly overhauled basic to bring in Koenig lookup, we did not overhaul dcl.dcl as diligently as we should have (time pressure being the biggest factor).
As a result, I tend to read the standard with basic taking precedence over any conflicting information in other parts of the document. But this is not a definitive solution and the standard needs to be totally unambiguous without resorting to knowledge of its history.
Perhaps a better route would be for us to task ourselves with minutely examining dcl.dcl with an eye toward removing what is redundant and fixing what is in conflict with basic , rather than tackling each issue as they come up. This should enable us to approach the other known and unknown issues regarding dcl.dcl in a consistent fashion.
Mike Miller (core-7996) I think such a review would be a good idea.
However, I don't believe this issue falls into the "redundant and/or conflicting" category. namespace.udecl paragraph 10 is basically a cross-reference to the appropriate material in basic , with an extended example of how those general rules apply in the context of using-declarations.
namespace.udecl paragraph 11 deals with a situation that can only arise with using-declarations (two identical function declarations in the same block or namespace scope that refer to different functions), so it's appropriate to deal with it there. The only problem was that it didn't take extern "C" into account in the specification.
Proposed Resolution (Dublin '99)
Apply the change suggested by Mike Miller by replacing namespace.udecl paragraph 11 by:
If a function declaration in namespace scope or block scope has the same name and the same parameter types as a function introduced by a using-declaration, and the declarations do not declare the same function, the program is ill-formed.
See also: Core issue 11
Daveed Vandevoorde in core-8008: While reading core issue 11 I thought it implied the following possibility:
However, the grammar for a using-declaration reads:
and nested-name-specifier never ends in "template".
Is that intentional?
Bill Gibbons in core-8010:
It certainly appears to be, since we have:
>From reflector messages core-8001 and core-8003.
Section namespace.udir paragraph 4 uses the term extended-namespace-definition three times:
If a namespace is extended by an extended-namespace-definition after a using-directive for that namespace is given, the additional members of the extended namespace and the members of namespaces nominated by using-directives in the extended-namespace-definition can be used after the extended-namespace-definition.I think the intent is clear, but unfortunately I cannot find any other mention (or definition) of this term.
Mike Miller: True enough; in Section namespace.def [the grammar] it's called an extension-namespace-definition.
Proposed Resolution (Dublin '99)
Systematically replace "extended-namespace-definition" by "extension-namespace-definition".
(Previously numbered 864.)
7.5 para 6 says the following:
Tentative Resolution:
The intent is to distingush implicit linkage from explicit linkage for both name linkage and language (function type) linkage. (It might be more clear to use the terms name linkage and type linkage to distinguish these concepts. A function can have a name with one kind of linkage and a type with a different kind of linkage. The function itself has no linkage: it has no name, only the declaration has a name. This becomes more obvious when you consider function pointers.)
The tentatively agreed proposal is to apply implicit linkage to names declared in brace-enclosed linkage specifications and to non-top-level names declared in simple linkage specifications; and to apply exiplicit linkage to top-level names declared in simple linkage specifications.
The language linkage of any function type formed through a function declarator is that of the nearest enclosing linkage-specification. For purposes of determining whether the declaration of a namespace-scope name matches a previous declaration, the language linkage portion of the type of a function declaration (that is, the language linkage of the function itself, not its parameters, return type or exception specification) is ignored.
For a linkage-specification using braces, i.e.
extern string-literal { declaration-seqopt }the linkage of any declaration of a namespace-scope name (including local externs) which is not contained in a nested linkage-specification, is not declared to have no linkage (static), and does not match a previous declaration is given the linkage specified in the string-literal. The language linkage of the type of any function declaration of a namespace-scope name (including local externs) which is not contained in a nested linkage-specification and which is declared with function declarator syntax is the same as that of a matching previous declaration, if any, else is specified by string-literal.
For a linkage-specification without braces, i.e.
extern string-literal declarationthe linkage of the names declared in the top-level declarators of declaration is specified by string-literal; if this conflicts with the linkage of any matching previous declarations, the program is ill-formed. The language linkage of the type of any top-level function declarator is specified by string-literal; if this conflicts with the language linkage of the type of any matching previous function declarations, the program is ill-formed. The effect of the linkage-specification on other (non top-level) names declared in declaration is the same as that of the brace-enclosed form.
[This needs additional drafting work.]
(Previously numbered 921.)
How can we write a function template, or member function of a class template that takes a C linkage function as a parameter when the function type depends on one of the template parameter types?
Somehow permit a language linkage to be specified as part of a function parameter declaration. i.e.
The whole area of linkage needs revisiting. Declaring calling
convention as a storage class was incorrect to begin
with; it should be a function qualifier, as in:
And to that end, I suggest that the use of linkage specifiers to specify
calling convention be deprecated - which would make any use of linkage
specifiers in a parameter declaration deprecated.
(Previously numbered 922.)
Issue 1
dcl.link paragraph 6 says the following:
Rationale:
Not a defect; these are the same function for all purposes.
Issue 2
A similar question may arise with typedefs:
Tentative Resolution:
In namespace.udir paragraph 4:
If name lookup finds a declaration for a name in two different namespaces, and the declarations do not declare the same entity and do not declare functions, the use of the name is ill-formed.The term entity applied to typedefs refers to the underlying type or class; so the above example is well-formed.
The CWG at Dublin '99 agreed with this resolution and consequently moved this issue to become "NAD".
Proposed Resolution (Mike Miller)
There are two questions, summarized in the following example:
Analysis
The Standard specifies the criteria for ambiguity in the presence of using-declarations in namespace.udir paragraph 4:
The question of whether the two typedef declarations cause an ambiguity is more involved. According to basic paragraph 3,
Proposed Resolution
In order to make the treatment of typedef names clearer, a typedef should be added to the example in namespace.udir paragraph 4:
However, in the interest of reducing the number of changes to the standard, the CWG at Dublin '99 agreed to not move this change in non-normative text to become a defect.
From reflector message core-7714
Consider the following:
The ARM is explicit and says
A linkage-specification for a function also applies to functions and objects declared within it.The DIS says
In a linkage-specification, the specified language linkage applies to the function types of all function declarators, function names, and variable names introduced by the declaration(s).Is the body of a function definition part of the declaration?
I find all sorts of guidance but no hard statement about this. I wasn't in on the discussions of the subject. Can someone please enlighten me as to the intent? (broader enlightenment seems a lot to ask of a language standard :-)
From Mike Miller:
Yes: from 7p1,
From Dag Bruck:
As a follow up to Mike Ball's message c++std-core-7714, consider the following where extern "C" has been moved to a separate declaration:
As a side note, I have always wanted to think that placing extern "C" on a function definition or a separate declaration would produce idential programs.
Tentative Resolution:
See the tentative resolution for Core issue 4 , which covers this case.
The ODR should also be checked to see whether it addresses name and
type linkage.
From reflector message core-8020, 8021:
Steve Clamage: I can't find anything in the standard that prohibits a language linkage on an operator function. For example:
extern "C" int operator+(MyInt, MyInt) { ... }
Clearly it is a bad idea, you could have only one operator+ with "C" linkage in the entire program, and you can't call the function from C code.
Mike Miller: Well, you can't name an operator function in C code, but if the arguments are compatible (e.g., not references), you can call it from C code via a pointer. In fact, because the language linkage is part of the function type, you couldn't pass the address of an operator function into C code unless you could declare the function to be extern "C".
Fergus Henderson: In the general case, for linkage to languages other than C, this could well make perfect sense.
Steve Clamage:
But is it disallowed (as opposed to being stupid), and if so, where in the standard does it say so?
Mike Miller: I don't believe there's a restriction. Whether that is because of the (rather feeble) justification of being able to call an operator from C code via a pointer, or whether it was simply overlooked, I don't know.
Fergus Henderson:
I don't think it is disallowed. I also don't think there is any need
to explicitly disallow it.
From reflector message core-7835
Minor editorial nits in 8.3p1:
The id-expression of a declarator-id shall be a simple identifier except...This is, from the list of exceptions, intended to allow for multi-token names. However, the wrong syntactic category was chosen; restricting the id-expression to an identifier has the effect of forbidding all qualified names. Probably the best fix is to replace "id-expression" with "unqualified-id."
A declarator-id shall not be qualified except for the definition of a... nested class (9.7) outside of its class.The problem here is that the name of the class in a class definition is not a declarator-id, so the "nested class" case does not belong in this list.
More Analysis (Mike Miller)
There are two sub-issues. The first concerns the statement in dcl.meaning paragraph 1,
The id-expression of a declarator-id shall be a simple identifier except for the declaration of some special functions (class.conv , class.dtor , over.oper ) and for the declaration of template specializations or partial specializations (temp.spec ).The second sub-issue is regarding another statement in the same paragraph:
A declarator-id shall not be qualified except for the definition of a member function (class.mfct ) or static data member (class.static ) or nested class (class.nest ) outside of its class, the definition or explicit instantiation of a function, variable or class member of a namespace outside of its namespace, or...Analysis
The problem in the first sub-issue is that the wrong syntactic non-terminal is mentioned. The relevant portions of the grammar are:
If an unqualified-id is used as the id-expression of a declarator-id, it shall be a simple identifier except...However, it does not appear that this restriction has any meaning; all of the possible cases of unqualified-ids are represented in the list of exceptions! Rather than recasting the sentence into a correct but useless form, it would be better to remove it altogether.
The second sub-issue deals with the conditions under which a qualified-id can be used in a declarator, including "the definition of a...nested class" and "the definition or explicit instantiation of a...class member of a namespace." However, the name in a class definition is not part of a declarator; these constructs do not belong in a list of declarator contexts.
The second sub-issue above was overlooked at Dublin '99 and still needs to be closed.
Resolution (Dublin '99, for the first sub-issue above) Change [dcl.meaning ] 8.3/1 from:
The id-expression of a declarator-id shall be a simple identifier except...to:
An unqualified-id occuring in a declarator-id shall be a simple identifier except...
(Previously numbered 929.)
8.3.5 para 2 says:
If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list.Can a typedef to void be used instead of the type void in the parameter list?
Rationale:
The IS is already clear that this is not allowed.
(Previously numbered 689.)
3.3 para 3 says:
Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,8.3.6 para 9 says:
- they shall all refer to the same entity, or all refer to functions ...
When a declaration of a function is introduced by way of a using declaration, any default argument information associated with the declaration is imported as well.This is not really clear regarding what happens in the following case:
Add the following at the end of [over.match.best] 13.3.3:
If the best viable function resolves to a function for which multiple declarations were found, and if at least two of these declarations specify a default argument that made the function viable, the program is ill-formed.[ Example: namespace A { extern "C" void f(int = 5); } namespace B { extern "C" void f(int = 5); } using A::f; using B::f; void use() { f(3); // OK, default argument was not used for viability f(); // Error: found default argument twice! } --End example ]
This wording needs some work to "see through" using-declarations.
(Previously numbered 923.)
8.3.6 para 4 says:
For non-template functions, default arguments can be added in later declarations of a functions in the same scope.Why say for non-template functions? Why couldn't the following allowed?
Rationale:
This is sufficiently clear in the standard. Allowing additional
default arguments would be an extension.
Resolution (Dublin '99)
Change text in the example of section [dcl.fct.default
] 8.3.6/5
from:
... g will be called with the value f(1).to:
... g will be called with the value f(2).
Paragraph 9 of says that extra default arguments added after a using-declaration but before a call are usable in the call, while 7.3.3p9 says that extra
function overloads are not. This seems inconsistent, especially given
the similarity of default arguments and overloads.
(Previously numbered 866.)
The description of copy-initialization in 8.5 para 14 says:
Tentative Resolution:
As above. Steve Adamczyk will draft the clarification.
From reflector message core-7780
Given:
Simiarly, S2().x and S2().y are also defined to be equal to zero, and here it really matters for many implementations, because if S2().y is just a bunch of random bits, it is entirely possible that trying to copy S2().y will yield a floating-point trap.
However, rather to my surprise, the standard does not define the value of S3().x or S3().y, because S3 is not a POD. It does define S3().s (by running the string constructor), but once a structure is no longer a POD, the values of uninitialized members are no longer guaranteed in expressions of the form T().
In my opinion, this definition is a mistake, and the committee's intention was to zero-initialize all members that do not have an explicitly defined constructor, whether or not the class is a POD.
See core reflector messages 7780, 7782, 7785-7787, 7789-7791, 7796 and 7798-7805 for a spirited discussion of this topic. Also see 98-0018/N1161.
Resolution (Dublin '99)
Add the following text to the end of section [dcl.init ] 8.5/5:
To value-initialize an object of type T means:
- if T is a class type (_class_) with a user-declared constructor (_class.ctor_), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
- if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
- if T is an array type, then each element is value-initialized;
- otherwise, the storage for the object is zero-initialized.
Change "default-initialization" to "value-initialization" in 5.2.3 paragraph 2 and in 8.5.1 paragraph 7.
Paragraph 9 of dcl.init says:
If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for an object, the object and its subobjects, if any, have an indeterminate initial value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.It should be made clear that this paragraph does not apply to static objects.
Tentative Resolution: Put the word "non-static" before "object".
In class.name paragraph 2, there is the example
See also
Core issue 36
and
Core issue 56
.
From reflector message core-7936
The standard says, in class.mem paragraph 4:
A member-declarator can contain a constant-initializer only if it declares a static member (class.static ) of integral or enumeration type, see class.static.data .But later, in the section on static class data member initialization, class.static.data paragraph 4, it says:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (expr.const ). In that case, the member can appear in integral constant expressions within its scope.The first paragraph should be modified to make it clear that it is not possible to initialize a static data member in-line with a constant-initializer if that data member is of integral (or enumeration) type, and yet not const.
Proposed Resolution (Dublin '99)
Change the sentence in class.mem paragraph 4 to read:A member-declarator can contain a constant-initializer only if it declares a static member (class.static ) of const integral or const enumeration type, see class.static.data .
From reflector message core-7917
Between the May '96 and September '96 working papers, the text in class.mem paragraph 13:
If T is the name of a class, then each of the following shall have a name different from T:was changed by removing the word 'static'. Looking over the meeting minutes from Stockholm, none of the proposals seem to include this change, which breaks C compatibility and is not mentioned in the compatibility annex. Was this change actually voted in by the committee?
- every static data member of class T;
Specifically, this breaks /usr/include/netinet/in.h under Linux,
in which "struct ip_opts" shares its name with one of its members.
Paragraph 2 says that "the object-expression is always evaluated" when the class member syntax is used to refer to a static member. This presumably should say that the object expression is evaluated if the member access is performed, i.e., not if the overall expression is the operand of sizeof or the unevaluated branch of ?:, ||, or &&.
Proposed Resolution (Dublin '99)
Replace "is always evaluated" by "is evaluated" in class.static paragraph 2.
Also see section: 3.2 [basic.def.odr].
Originally, all static data member still had to be defined outside the class whether they were used or not.
But that restriction was supposed to be lifted so that static data members need not be defined outside the class unless they are used in a manner which requires their definition, in the same manner as namespace-scope variables. In particular, if an integral/enum const static data member is initialized within the class, and its address is never taken, we agreed that no namespace-scope definition was required.
For example:
The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.A narrow interpreration of "used" in this rule would make the example ill-formed because there is no namespace-scope definition of "size". A better wording for this rule would be:
The member shall still be defined in a namespace scope if it is used in the program in the manner described in 3.2 (_basic.def.odr_). The namespace scope definition shall not contain an initializer.Also, the wording in 3.2/2:
An expression is potentially evaluated unless either it is the operand of the sizeof operator (_expr.sizeof_), or it is the operand of the typeid operator and does not designate an lvalue of polymorphic class type (_expr.typeid_).is incomplete because it does not mention the use of a compile-time constant as an array bound or template argument. It should say something like:
An expression is potentially evaluated unless it is the operand of the sizeof operator (_expr.sizeof_), the operand of the typeid operator, an integral constant-expression used as an array bound or an integral constant-expression used as a template-argument for a non-reference template-parameter; and the expression does not designate an lvalue of polymorphic class type (_expr.typeid_).
Resolution (Dublin '99)
Change the first sentence of [basic.def.odr ] 3.2/2 from:
An expression is potentially evaluated unless either it is the operand of the sizeof operator (5.3.3), or it is the operand of the typeid operator and does not designate an lvalue of polymorphic class type (5.2.8).to:
An expression is potentially evaluated unless it appears where an integral constant expression is required (see _expr.const_), is the operand of the sizeof operator (_expr.sizeof_), or is the operand of the typeid operator and the expression does not designate an lvalue of polymorphic class type (_expr.typeid_).
There doesn't seem to be a prohibition in 9.5 against a declaration like
What about:
Section 9.6/4 needs to be more specific about the signedness of bit
fields of enum type. How much leeway does an implementation have
in choosing the signedness of a bit field? In particular, does the
phrase "large enough to hold all the values of the enumeration" mean "the
implementation decides on the signedness, and then we see whether all the
values will fit in the bit field", or does it require the implementation
to make the bit field signed or unsigned if that's what it takes to make
it "large enough"?
From reflector message core-7816
The ambiguity text in 10.2 may not say what we intended. It makes the following example ill-formed:
... Each of these declarations that was introduced by a using-declaration is considered to be from each sub-object of C that is of the type containing the declaration designated by the using-declaration. If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed.This contradicts the text and example in paragraph 12 of 7.3.3.
Tentative Resolution:
The above example should be well-formed. Neal Gafter will propose revised
wording.
(Previously numbered 898.)
Consider the following example:
In clause 11 paragraph 5 we have:
Rationale:
Not a defect. This behavior is as intended.
ISSUE 2:
Now consider void A::int_temp<A::A1, A::garbconst + 2, &A::func>::func1() {...} By my reading of 11.8 [class.access.nest], the references to A::A1, A::garbconst and A::func are now illegal, and there is no way to define this function outside of the class. Is there any need to do anything about either of these Issues?
This issue needs work.
(Previously numbered 888.)
In short, it looks like a class with a virtual private base can't be derived from.
Rationale:
This is what was intended.
(Previously numbered 899.)
11.2 para 4 says:
A base class is said to be accessible if an invented public member of the base class is accessible. If a base class is accessible, one can implicitly convert a pointer to a derived class to a pointer to that base class.Given the above, is the following well-formed?
1st interpretation:
A public member of B is accessible within foo (since foo is a friend), therefore foo can refer to b1 and convert a D* to a B*.
2nd interpretation:
B is a protected base class of D, and a public member of B is a protected member of D and can only be accessed within members of D and friends of D. Therefore foo cannot refer to b1 and cannot convert a D* to a B*.
Tom Wilcox wrote a paper N1179 on issues 9, 16, 17 and 19 for the Dublin '99 meeting. He will amend the paper as discussed at that meeting.
(Previously numbered 924.)
The text in 11.2 para 4 does not seem to handle the following cases:
Tom Wilcox wrote a paper N1179 on issues 9, 16, 17 and 19 for the Dublin '99 meeting. He will amend the paper as discussed at that meeting.
(Previously numbered 925.)
Footnote 98 says:
As specified previously in clause _class.access_, private members of a base class remain inaccessible even to derived classes unless friend declarations within the base class declaration are used to grant access explicitly.This footnote does not fit with the algorithm provided in 11.2 para 4 because it does not take into account the naming class concept introduced in this paragraph.
Tom Wilcox wrote a paper N1179 on issues 9, 16, 17 and 19 for the Dublin '99 meeting. He will amend the paper as discussed at that meeting.
The definition of "friend" in class.friend says:
A friend of a class is a function or class that is not a member of the class but is permitted to use the private and protected member names from the class. ...A nested class, i.e. INNER in the example below, is a member of class OUTER. The sentence above states that it cannot be a friend. I think this is a mistake.
(Previously numbered 930.)
11.5 para 1 says:
When a friend or a member function of a derived class references a protected nonstatic member of a base class, an access check applies in addition to ...Instead of saying "references a protected nonstatic member of a base class", shouldn't this be rewritten to use the concept of naming class as 11.2 para 4 does?
Tom Wilcox wrote a paper N1179 on issues 9, 16, 17 and 19 for the Dublin '99 meeting. He will amend the paper as discussed at that meeting.
(Previously numbered 900.)
Paragraph 1 says: "The members of a nested class have no special access to members of an enclosing class..."
This prevents a member of a nested class from being defined outside of its class definition. i.e. Should the following be well-formed?
This issue depends on the outcome of
Core issue 45
.
From reflector message core-7855
Example:
[class.access] 11/1: 1 A member of a class can beand
- private; that is, its name can be used only by members and friends of the class in which it is declared. [...]
[class.access.nest] 11.8/1: 1 The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause _class.access_) shall be obeyed. [...]This makes me think that the ': Parent' part is OK by itself, but that the implicit call of 'Parent::Parent()' by 'Derived::Derived()' is not.
From Mike Miller:
I think it is completely legal, by the reasoning given in the (non-normative) 11.8p2. The use of a private nested class as a base of another nested class is explicitly declared to be acceptable there. I think the rationale in the comments in the example ("// OK because of injection of name A in A") presupposes that public members of the base class will be public members in a (publicly-derived) derived class, regardless of the access of the base class, so the constructor invocation should be okay as well.
I can't find anything normative that explicitly says that, though.
Tentative Resolution:
A member classes should have access to the members of the enclosing
class in the same manner as if it had been declared a friend of the enclosing
class. Steve Adamczyk will write a proposal for this change.
In class.temporary paragraph 5, should binding a reference to the result of a "?" operation, each of whose branches is a temporary, extend both temporaries?
Here's an example:
(Previously numbered 876b.) Mike Miller wrote paper N1182==99-0005 to discuss this topic. The CWG at Dublin '99 agreed that this is an extension request, but that the resolution proposed in N1182 is desirable.
At the London meeting, 12.8 [class.copy] paragraph 15 was changed to limit the optimization described to only the following cases:
Can we find an appropriate description for the desired cases?
Proposed Resolution (Mike Miller)
This issue deals with describing conditions that allow copy operations to be eliminated by a conforming implementation. class.copy paragraph 15 currently describes two such situations. The Committee agreed that a third such optimization would also be desirable: suppression of the copy from an argument to a non-reference parameter in a call to an inline function. However, wording to describe when such an elision would be allowed has not been produced.
Analysis
The "as-if" rule (intro.execution paragraph 1) allows an implementation to eliminate operations if it can be determined that the observable behavior of the program will not be affected by the optimization. However, because copy constructors and destructors can have side effects that do alter the program's observable behavior, copy operations cannot in general be elided under the as-if rule alone. class.copy paragraph 15 relaxes the requirements of the as-if rule by allowing an implementation to optimize away certain copy operations, even if side effects in the no-longer-called copy constructor and destructor would have produced different observable behavior. Nevertheless, apart from the absence of these side effects, the remaining semantic constraints must be honored.
For the situations currently described in class.copy paragraph 15, these constraints boil down to the requirement that the copy constructor be accessible and unambiguous. In the function parameter optimization, however, additional constraints apply; in particular, none of the operations of the function can be allowed to change the value of the object passed as an argument. Furthermore, changes to a volatile object passed as an argument must not affect the value of the parameter during the execution of the function.
Although the issue is written specifically to address inline functions, there seems to be no reason to preclude applying the optimization to non-inline functions as well.
Proposed Resolution
Add the following bullet to the list of permissible optimizations in class.copy paragraph 15. (The form of this proposed change assumes the restructuring proposed below for the resolution of Core issue 20 .)
Erwin Unruh: Please think about the idea of doing such an optimization in only some calls of the function. As an example see the following code:
If this could be accepted, in the text below the words "can change the
value" should be replaced by "changes the value". So only if the function
incarnation does change some member, then this optimization is disallowed.
(Previously numbered 931.)
Issue 1
class.copy paragraph 15 describes the elimination of calls to copy constructors. The text should be clear that the access check and ambiguity check on the copy constructor are still performed even though the copy constructor is not called.
Also, in the example:*
* The example should make it clear that two calls to Thing's copy constructor are eliminated.
Rationale:
The standard makes it clear which calls may be eliminated.
Issue 2
However, the order in which the elision is done interacts with the specification of the point of destruction in a way which needs to be clearly specified. Mike Miller will write a proposal on this issue.
Proposed Resolution (Mike Miller)
There are three related sub-issues in this issue, all dealing with the elision of copy constructors as described in class.copy paragraph 15:
After discussion in Santa Cruz, the core group decided that sub-issue #1 required no change; the necessity of an accessible and unambiguous copy constructor is made clear in class.temporary paragraph 1 and need not be repeated in this text. The remaining two sub-issues appear to be valid criticisms and should be addressed.
Proposed Resolution
(See also paper N1182 by Mike Miller---the paper was approved by the CWG at Dublin '99)
The paragraph in question should be rewritten as follows. (Note: this restructuring is also intended to facilitate the inclusion of the proposal to resolve Core issue 6 .) In addition, references to this section should be added to the index under "temporary, elimination of," "elimination of temporary," and "copy, constructor elision."
>From reflector message core-7647
The working paper is quite explicit about
Shouldn't it be as explicit about the following?
There is no need for additional wording. This example leads to
a program which either fails to compile (due to resource limits on recursive
inlining) or fails to run (due to unterminated recursion). In either case
the implementation may generate an error when the program is compiled.
>From reflector messages 7864, 7870, 7872, 7997.
The following example does not work as one might expect:
Daveed Vandevoorde: (core-7870) But doesn't unqualified lookup of the operator+ in the definition of std::accumulate proceed in the namespace where the implicit specialization is generated; i.e., in namespace std?
In that case, you may find a non-empty overload set for operator+ in namespace std and the surrounding (global) namespace is no longer considered?
Nathan Myers: (core-7872) Indeed, <string> defines operator+, as do <complex>, <valarray>, and <iterator>. Any of these might hide the global operator.
Herb Sutter: (core-7997) These examples fail for the same reason:
Bill Gibbons: It looks like part of this problem is that the library is referring to names which it requires the client to declare in the global namespace (the operator names) while also declaring those names in namespace std. This would be considered very poor design for plain function names; but the operator names are special.
There is a related case in the lookup of operator conversion functions. The declaration of a conversion function in a derived class does not hide any conversion functions in a base class unless they convert to the same type. Should the same thing be done for the lookup of operator function names, e.g. should an operator name in the global namespace be visible in namespace std unless there is a matching declaration in std?
Because the operator function names are fixed, it it much more likely that a declaration in an inner namespace will accidentally hide a declaration in an outer namespace, and the two declarations are much less likely to interfere with each other if they are both visible.
The lookup rules for operator names (when used implicitly) are already quite different from those for ordinary function names. It might be worthwhile to add one more special case.
Mike Ball @Dublin '99: The original SGI proposal said that non-transitive points of instantiation were also considered. Why, when and by who was is added?
Sections over.match.copy and over.match.conv should be clarified regarding the treatment of conversion functions which return reference types.
Proposed resolution:
In over.match.copy paragraph 1, change
Conversion functions that return "reference to T" return lvalues of type T and are therefore considered to yield T for this process of selecting candidate functions.to
Conversion functions that return "reference to X" return lvalues of type X and are therefore considered to yield X for this process of selecting candidate functions.In over.match.conv paragraph 1, change
Conversion functions that return "reference to T" return lvalues of type T and are therefore considered to yield T for this process of selecting candidate functions.to
Conversion functions that return "reference to cv2 X" return lvalues of type "cv2 X" and are therefore considered to yield X for this process of selecting candidate functions.
In 13.3.3/1, bullet 4 of the second set of bullets, there is a cross-reference to 8.5 and 13.3.1.5. I believe it should also reference 13.3.1.6 (over.match.ref). I think the phrase "initialization by user-defined conversion" was intended to refer to all initalizations using user-defined conversions, and not just the case in 13.3.1.5. Referring to only 13.3.1.5 suggests a narrower meaning of the phrase.
13.3.1.4, although it does deal with initialization by user-defined
conversion, does not need to be referenced because it deals with class
--> class cases, and therefore there are no standard conversions involved
that could be compared.
By the letter of the standard, the conversions required to make auto_ptr work should be accepted.
However, there's good reason to wonder if there isn't a bug in the standard here. Here's the issue: line 16 in the example below comes down to
copy-initialize an auto_ptr<Base> from an auto_ptr<Derived> rvalueto do that, we first look to see whether we can convert an auto_ptr<Derived> to an auto_ptr<Base>, by enumerating the constructors of auto_ptr<Base> and the conversion functions of auto_ptr<Derived>. There's a single possible way to do the conversion, namely the conversion function
So far, so good. Now, we do the copy step:
direct-initialize an auto_ptr<Base> from an auto_ptr<Base> rvalueThis, as we've gone to great lengths to set up, is done by calling the conversion function
The problem with this interpretation is that it violates the long-standing common-law rule that only a single user-defined conversion will be called to do an implicit conversion. I find that pretty disturbing. (In fact, the full operation involves two conversion functions and two constructors, but "copy" constructors are generally considered not to be conversions.)
The direct-initialization second step of a copy-initialization was intended
to be a simple copy -- you've made a temporary, and now you use a copy
constructor to copy it. Because it is defined in terms of direct
initialization, however, it can exploit the loophole that auto_ptr
is based on.
To switch to personal opinion for a second, I think it's bad enough that auto_ptr has to exploit a really arcane loophole of overload resolution, but in this case it seems like it's exploiting a loophole on a loophole.
Does dropping a cv-qualifier on a reference binding prevent the binding
as far as overload resolution is concerned? Paragraph 4 says "Other restrictions
on binding a reference to a particular argument do not affect the formation
of a conversion sequence."; This was intended to refer to things like access
checking, but some readers have taken that to mean that any aspects of
reference binding not mentioned in this section do not preclude the binding.
In over.ics.rank , we have
--S1 and S2 differ only in their qualification conversion and yield similar types T1 and T2 (conv.qual ), respectively, and the cv-qualification signature of type T1 is a proper subset of the cv-qualification signature of type T2, [Example:This does not work right with respect to the deprecated conversion from string literal to "char *". Considerint f(const int *); int f(int *); int i; int j = f(&i); // Calls f(int *) --end example] or, if not that,
From reflector message core-7649
I understand that the lvalue-to-rvalue conversion was removed in London. I generally agree with this, but it means that ?: needs to be fixed:
Given:
(Not a problem in FDIS, but misleading.)
Rationale:
The description of the conditional operator in
expr.cond
handles the lvalue case before the prototype is considered.
Can p->f, where f refers to a set of overloaded functions
all of which are static member functions, be used as an expression in an
address-of-overloaded-function context? A strict reading of this
section suggests "no", because "p->f" is not the name of an overloaded
function (it's an expression). I'm happy with that, but the core
group should decide and should add an example to document the decision,
whichever way it goes.
From reflector message core-7766
Section 14/8 [temp] says:
A non-exported template that is neither explicitly specialized nor explicitly instantiated must be defined in every translation unit in which it is implicitly instantiated (_temp.inst_) or explicitly instantiated (_temp.explicit_); no diagnostic is required.Shouldn't the first underlined phrase be omitted to avoid conflict with the second underlined phrase?
From John Spicer:
The first "explicitly instantiated" is intended to mean "explicit instantiated in some other translation unit".
Resolution: (Dublin '99)
Change text in [temp ] 14/8 from:A nonexported template that is neither explicitly specialized nor explicitly instantiated must be defined in every translation unit in which it is implicitly instantiated (14.7.1) or explicitly instantiated (14.7.2); no diagnostic is required.to:
A non-exported template must be defined in every translation unit in which it is implicitly instantiated (14.7.1), unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required. [ Note: See also _temp.explicit_ ]
From reflector messages core-7876-7878
John Spicer: The standard does say that a namespace scope template has external linkage unless it is a function template declared "static". It doesn't explicitly say that the linkage of the template is also the linkage of the instantiations, but I believe that is the intent. For example, a storage class is prohibited on an explicit specialization to ensure that a specialization cannot be given a different storage class than the template on which it is based.
Mike Ball: This makes sense, but I couldn't find much support in the document. Sounds like yet another interpretation to add to the list.
John Spicer: The standard does not talk about the linkage of instantiations, because only "names" are considered to have linkage, and instances are not really names. So, from an implementation point of view, instances have linkage, but from a language point of view, only the template from which the instances are generated has linkage.
Mike Ball: Which is why I think it would be cleaner to eliminate storage class specifiers entirely and rely on the unnamed namespace. There is a statement that specializations go into the namespace of the template. No big deal, it's not something it says, so we live with what's there.
John Spicer: That would mean prohibiting static function templates. I doubt those are common, but I don't really see much motivation for getting rid of them at this point.
"export" is an additional attribute that is separate from linkage, but that can only be applied to templates with external linkage.
Mike Ball: I can't find that restriction in the standard, though there is one that templates in an unnamed namespace can't be exported. I'm pretty sure that we intended it, though.
John Spicer: I can't find it either. The "inline" case
seems to be addressed, but not static. Surely this is an error as,
by definition, a static template can't be used from elsewhere.
The phrase "template function" is sometimes used to refer to a template (e.g., in [temp ]/8) and sometimes to refer to a function generated from a template (e.g., [over.over ]/4).
Tentative Resolution:
The phrase should mean "a function generated from a template" (or might perhaps include explicit specializations).
The example in temp.dep.res paragraph 8 is:
w;
I've been looking for the verbiage that specifies that this is an error and haven't found it. In particular, nothing in 14.1 ("Template parameters") nor 14.3.2 ("Template non-type arguments") appears to rule out this case. (14.3.2p1 allows an argument to be "the name of an object or function with external linkage," with no limitation on the kinds of parameters such a name can match; "p" is, in fact, such a name.)
Should the resolution of the French comment include beefing up one or both of these sections to cover the applicable rules explicitly?
Resolution (Dublin '99)
Change the example from [temp.param ] 14.1/8 from:
template<int *a> struct R { /* ... */ };to:
template<int b[5]> struct S { /* ... */ };
int *p;
R<p> w; // OK
S<p> x; // OK due to parameter adjustment
int v[5];
R<v> y; // OK due to implicit argument conversion
S<v> z; // OK due to both adjustment and conversion
template<int *a> struct R { /* ... */ };
template<int b[5]> struct S { /* ... */ };
int p;
R<&p> w; // OK
S<&p> x; // OK due to parameter adjustment
int v[5];
R<v> y; // OK due to implicit argument conversion
S<v> z; // OK due to both adjustment and conversion
Furthermore, in [temp.arg.nontype] 14.3.2/1, the following should
be effected:
From reflector message core-7731
I have a request for clarification regarding a issue similar to John Wiegley's, but wrt. the ::template syntax. More precisely, where is
The question also holds for '.template' and '->template'.
Resolution (Dublin '99)
Append to [temp.names ] 14.2/5:
Furthermore, names of member templates shall not be prefixed by the keyword template if the postfix-expression or qualified-id does not appear in the scope of a template. [Note: just as is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the expression on the left of the -> or ., or the nested-name-specifier is not dependent on a template-parameter. ]
From reflector message core-7807
It appears from the grammar that explicit template arguments cannot be specified for overloaded operator names. Does this mean that template operators can never be friends?
But assuming that I read things wrong, then I should be able to specify a global template 'operator +' by writing:
You should be able to have explicit template arguments on operator function, but the grammer does seem to prohibit it (unless I'm reading it incorrectly). This is an error in the grammer, they should be permitted.
Tentative Resolution:
This is an oversight the grammer. John Spicer will draft a correction.
The following is the wording from temp.names paragraphs 4 and 5 that discusses the use of the "template" keyword following . or -> and in qualified names.
If a name prefixed by the keyword template is not the name of a member template, the program is ill-formed. [Note: the keyword template may not be applied to non-template members of class templates. ]
First, I think it should be made more clear that the template name must be followed by a template argument list when the "template" keyword is used in these contexts. If we don't make this clear, we would have to add several semantic clarifications instead. For example, if you say "p->template f()", and "f" is an overload set containing both templates and nontemplates: a) is this valid? b) are the nontemplates in the overload set ignored? If the user is forced to write "p->template f<>()" it is clear that this is valid, and it is equally clear that nontemplates in the overload set are ignored. As this feature was added purely to provide syntactic guidance, I think it is important that it otherwise have no semantic implications.
I propose that paragraph 5 be modified to:
Section 14.3.1 paragraph 2 says
A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.It probably wasn't intended that classes with unnamed members should be included in this list, but they are arguably compounded from unnamed types.
The explanation in temp.arg.nontype paragraph 2 of why a string literal cannot be used as a template argument leaves something to be desired:
...because a string literal is an object with internal linkage.I can't find anything that says that a string literal has internal linkage. In fact, I'd be pretty surprised if I did, since linkage is defined (in basic.link ) strictly in terms of names, and a string literal doesn't have a name. Actually, I think that it's the namelessness of a string literal that prevents it from being a template argument; only the third and fourth bullets of temp.arg.nontype paragraph 1 could conceivably apply, and both of those require that the entity have a name (i.e., that they be given as an id-expression).
Proposed Resolution (Dublin '99)
Replace "is an object with internal linkage" by "has no name" in temp.arg.nontype paragraph 2.
Issue 1
Paragraph 1 says that a friend of a class template can be a template. Paragraph 2 says: A friend template may be declared within a non-template class. A friend function template may be defined within a non-template class.
I'm not sure what this wording implies about friend template definitions within template classes. The rules for class templates and normal classes should be the same: a function template can be declared or defined, but a class template can only be declared in a friend declaration.
Issue 2
Paragraph 4 says: When a function is defined in a friend function declaration in a class template, the function is defined when the class template is first instantiated. I take it that this was intended to mean that a function that is defined in a class template is not defined until the first instantiation. I think this should say that a function that is defined in a class template is defined each time the class is instantiated. This means that a function that is defined in a class template must depend on all of the template parameters of the class template, otherwise multiple definition errors could occur during instantiations. If we don't have a rule like this, compilers would have to compare the definitions of functions to see whether they are the same or not. For example:
From Bill Gibbons:
[1] That sounds right.
[2] Whenever possible, I try to treat instantiated class templates as if they were ordinary classes with funny names. If you write:
The CWG at Dublin '99 agreed with the conclusion of the second issue (the
example program is ill-formed), but believes this is not a defect (i.e., it can already be deduced from the standard). The first issue appears to no longer be in synch with the standard.
(Previously numbered 934.)
Issue 1:
14.5.5.2 para 2 says:
Given two overloaded function templates, whether one is more specialized than another can be determined by transforming each template in turn and using argument deduction (14.8.2) to compare it to the other.14.8.2 now has 4 subsections describing argument deduction in different situations. I think this paragraph should point to a subsection of 14.8.2.
Rationale:
This is not a defect; it is not necessary to pinpoint cross-references to this detail.
Issue 2:
14.5.5.2 para 4 says:
Using the transformed function parameter list, perform argument deduction against the other function template. The transformed template is at least as specialized as the other if, and only if, the deduction succeeds and the deduced parameter types are an exact match (so the deduction does not rely on implicit conversions).In "the deduced parameter types are an exact match", the terms exact match do not make it clear what happens when a type T is compared to the reference type T&. Is that an exact match?
John Spicer will propose a resolution, which may or may not require a change to the standard.
Issue 3:
14.5.5.2 para 5 says:
A template is more specialized than another if, and only if, it is at least as specialized as the other template and that template is not at least as specialized as the first.What happens in this case:
Rationale:
This is not a defect; the standard unambiguously makes the above example
ill-formed due to ambiguity.
core-8011, core-8016:
Mark Mitchell (c/o John Spicer): Given:
Is this legal? The question really boils down to asking whether or not I1 is a dependent type. On the one hand, it doesn't seem to fit any of the qualifications in temp.dep.type . On the other, [temp.expl.spec ] allows explicit specialization of a member class of a class template, so something like:
is apparently legal. But, then, `X' no longer refers to a type name. So, it seems like `I1' should be classified as dependent. What am I missing?
Erwin Unruh: I did wrote that particular piece of text and I just
missed the problem above. It is intended to be a dependent type. The
reasoning is that I1 is just a shorthand for S Tentative Resolution (Erwin Unruh) I think the list of what is a dependent type should be extended to cover
"a type declared and used within the same template" modulo of phrasing.
(Previously numbered 737.)
Proposed resolution: (John Spicer)
My opinion (which I think matches several posted on the reflector recently)
is that the out-of-class definition must match the declaration in the template.
In your example they do match, so it is well formed.
I've added some additional cases that illustrate cases that I think
either are allowed or should be allowed, and some cases that I don't think
are allowed.
Declarations like Foo::i and Foo::j are invalid because
for a given instance of A<T>, A<T>::X may not actually
be int if the class is specialized.
This is not a problem for Foo::g1 and Foo::g2 because
for any instance of Foo<T> that is generated from the template
you know that Bar will always be int. If an instance of Foo is
specialized, the template member definitions are not used so it doesn't
matter whether a specialization defines Bar as int or not.
John Spicer will propose a clarification.
(Previously numbered 932.)
14.1 para 10 says:
i.e.
(Previously numbered 933.)
14.1 para 13 says:
Resolution (Dublin '99)
From reflector message core-7772
Does Koenig lookup create a point of instantiation for class types?
I.e., if I say:
Or should this be special cased for templates?
Rationale:
The standard already specifies that this creates a point of instantiation.
A template is implicitly instantiated because of a "pointer conversion"
on an argument. This was intended to include related-class conversions,
but it also inadvertently includes conversions to void*, null
pointer conversions, cv-qualification conversions and the identidy conversion.
It is not clear whether a reinterpret_cast of a pointer should
cause implicit instantiation.
Is the second explicit instantiation below well-formed?
The CWG at Dublin '99 felt that this is not really worth a change, and that the code could be considered illegal by [def.undefined] 1.3.12
(Previously numbered 839.)
[N1065 issue 1.19] An explicit specialization declaration may not be
visible during instantiation under the template compilation model rules,
even though its existence must be known to perform the instantiation correctly.
For example:
translation unit #1
This issue was addressed in the FDIS and should have been closed.
(Previously numbered 935; revised by Robert Klarer.)
Problem Description: Proposed Resolution: (Robert Klarer) 4. Remove the spurious semi-colon (or the curly brackets) from the end of the last line in the example in paragraph 17. This is the example as it
appears in the IS:
5. Remove spurious semi-colons (or curly brackets) from the specializations of mf1 and mf2 in example in paragraph 18. This is the text of the example as it appears in the IS:
From reflector message core-7851
Some compilers reject the following:
Was it the intent of the committee to forbid the construction above?
(Note that A itself is not a template.) If so, why?
Tentative Resolution:
(Although the CWG at Dublin '99 largely supported this resolution, it was not found acceptable by the full committee. The status thus returned to "open".)
Change the text in
temp.expl.spec
paragraph 17 from
Paragraph 12 should address partial ordering. It wasn't updated
when that change was made and conflicts with 14.5.5.2/1.
Is this valid C++? The question is whether a member constant can be specialized.
My inclination is to say no.
The program would be valid if the initializer were removed from the
specialization.
Daveed Vandevoorde: Or at least, the specialized member should
not be allowed in constant-expressions.
Bill Gibbons: Alternatively, the use of a member constant within
the definition could be treated the same as the use of "sizeof(member
class)". For example:
Consider:
John Spicer:
The partial ordering rules as originally proposed specified that, for
purposes of comparing parameter types, you remove a top level reference,
and after having done that you remove top level qualifiers. This is not
what is actually in the FDIS however. The FDIS says that you remove top
level qualifiers and then top level references.
The original rules were intended to prefer f(A<T>) over f(const T&).
Paragraph 4 lists contexts in which template formals are not deduced.
Were template formals in an expression in the array bound of an array type
specification intentionally left out of this list? Or was the intent
that such formals always be explicitly specified? Otherwise I believe the
following should be valid:
From John Spicer:
Expressions involving nontype template parameters are nondeduced contexts,
even though they are omitted from the list in 14.8.2.4p4. See 14.8.2.4p12...14:
...
At the top of clause 15, in paragraph 2, it says:
John Spicer: (core-7883) Our interpretation has been that all transfers into try blocks and handlers
are prohibited.
>From reflector message core-8002.
Questions regarding when a throw-expression temporary object is destroyed.
Section except.throw
paragraph 4 describes when the temporary is destroyed when a handler is found.
But what if no handler is found:
Or what if an exception specification is violated? There are several
different scenarios here:
(Previously numbered 936.)
15.4 para 3 should say what happens when two pointers to members with
different exception specifications are assigned to each other, initialized
with one another, etc.
Resolution (Dublin '99) Change the text in [except.spec
] 15.4/3 from:
In
except.spec
paragraph 2:
However, if exception specifications are made part of a function's type
as has been tentatively agreed, they would have to be allowed on any function
declaration.
It was tentatively agreed at the Santa Cruz meeting that exception specifications
should fully participate in the type system.
This is such a major change that it deserves to be a separate issue.
See also Core issue 25
and Core issue 87
.
From reflector message core-7806:
The term "throw exception" seems to sometimes refer to an expression
of the form "throw expr" and sometimes just to the "expr"
portion thereof.
As a result it is not quite clear to me whether when "uncaught_exception()"
becomes true: before or after the temporary copy of the value of "expr".
Is there a definite consensus about that?
Rationale:
The standard is sufficiently clear; the phrase "to be thrown" indicates
that the throw itself (which includes the copy to the temporary object)
has not yet begun. The footnote in except.terminate paragraph 1 reinforces
this ordering.
From reflector message core-7932
The example in lib.new.delete.placement
reads:
From reflector message core-7883
Annex D lists C compatibility issues. One item not in the annex came
up in a discussion in comp.std.c++.
Consider this C and C++ code:
The main defect is in the library, where the binder template can easily lead to reference-to-reference situations. Stroustrup's paper N1188 contains a details discussion (Dublin). Andrew Koenig illustrates the problem with the following example: The CWG at Dublin '99 did not see major problem with the proposed resolution of having multilevel references be equivalent to a plain single-level reference. The question was raised of whether multilevel references should be allowed as syntactic constructs, and Daveed Vandevoorde noted that this would introduce another situation where programmers may be surprised by the need for whitespace:
2. How can dependent names be used in member declarations that appear outside of the class template definition?
Section: 14.6.4 temp.dep.res
Status: open Submitter: unknown Date: unknown
21. Can a default argument for a template argument appear in a friend declaration?
Section: 14.6.4 temp.dep.res
Status: open Submitter: unknown Date: unknownThe set of default template-arguments available for use with
a template declaration or definition is obtained by merging the default
arguments from the definition (if in scope) and all declarations in scope
in the same way as default function arguments are (8.3.6)."
Can a default argument for a template argument appear in a friend declaration?
And if so, when is this default argument considered for template instantiations?
22. Template parameter with a default argument that refers to itself
Section: 14.6.4 temp.dep.res
Status: closed Submitter: unknown Date: unknownThe scope of a template-parameter extends from its point of
declaration until the end of its template. In particular, a template-parameter
can be used in the declaration of subsequent template-parameters and their
default arguments.
Is the following well-formed?
A templateparameter cannot be used in preceding templateparameters or their default arguments.
to:
A template-parameter cannot be used in preceding template-parameters, in their default arguments, or in its own default argument.
34. Argument dependent lookup and points of instantiation
Section: 14.7.1 temp.inst
Status: NAD Submitter: Daveed Vandevoorde Date: 15 Jul 1998
63. Class instantiation from pointer conversion to void*, null and self
Section: 14.7.1 temp.inst
Status: open Submitter: Steve Adamczyk Date: 13 Oct 1998
46. Explicit instantiation of member templates
Section: 14.7.2 temp.explicit
Status: NAD Submitter: John H. Spicer Date: 28 Jan 1998
3. The template compilation model rules render some explicit specialization declarations not visible during instantiation
Section: 14.7.3 temp.expl.spec
Status: NAD Submitter: Bill Gibbons Date: unknown
24. Typo in example 14.7.3 para 8
Section: 14.7.3 temp.expl.spec
Status: review Submitter: unknown Date: unknown
No program shall explicitly instantiate any template more than once, both explicitly instantiate and explicitly specialize a template, or specialize a template more than once for a given set of template arguments. An implementation is not required to diagnose a violation of this rule.
Proposed resolution:
44. Member specializations
Section: 14.7.3 temp.expl.spec
Status: open Submitter: Nathan Myers Date: 19 Sep 1998An explicit specialization shall be declared in the namespace
of which the template is a member, or, for member templates, in the namespace
of which the enclosing class or enclosing class template is a member. An
explicit specialization of a member function, member class or static data
member of a class template shall be declared in the namespace of which
the class template is a member. ...
claiming that the specialization above is not "in the namespace of which
the enclosing class ... is a member". Elsewhere, declarations are sometimes
required to be "at" or "in" "namespace scope", which is not what it says
here. Paragraph 17 says:
A member or a member template may be nested within many enclosing
class templates. If the declaration of an explicit specialization for such
a member appears in namespace scope, the member declaration shall be preceded
by a template<> for each enclosing class template that is explicitly
specialized.
The qualification "if the declaration ... appears in namespace scope",
implies that it might appear elsewhere. The only other place I can think
of for a member specialization is in class scope.
If the declaration of an explicit specialization for such a
member appears in namespace scope, the member declaration shall be preceded
by a template<> for each enclosing class template that is explicitly
specialized.
to
Any explicit specialization for such a member must be declared
at namespace scope. That declaration shall be preceded by a template<>
for each enclosing class template of the member declaration that is explicitly
specialized.
64. Partial ordering to disambiguate explicit specialization
Section: 14.7.3 temp.expl.spec
Status: open Submitter: Steve Adamczyk Date: 13 Oct 1998
88. Specialization of member constant templates
Section: 14.7.3 temp.expl.spec
Status: open Submitter: Jason Merrill Date: 20 Jan 1999
99. Partial ordering, references and cv-qualifiers
Section: 14.8.2.1 temp.deduct.call
Status: open Submitter: Mike Miller Date: 5 Mar 1999
70. Is an array bound a nondeduced context?
Section: 14.8.2.4 temp.deduct.type
Status: open Submitter: Jack Rouse Date: 29 Sep 1998
98. Branching into try block via switch label
Section: 15 except
Status: open Submitter: Jack Rouse Date: 23 Feb 1999
A goto, break, return, or continue statement can be used to transfer
control out of a try block or handler, but not into one.
What about switch statements?
104. Destroying the exception temp when no handler is found
Section: 15.1 except.throw
Status: open Submitter: Jonathan Schilling Date: 21 Mar 1999
25. Exception specifications and pointers to members
Section: 15.4 except.spec
Status: closed Submitter: unknown Date: unknownSimilarly, any function or pointer to function assigned to,
or initializing, a pointer to function shall only allow exceptions that
are allowed by the pointer or function being assigned to or initialized.
to:
A similar restriction applies to assignment to and initialization
of pointers to functions, pointers to member functions, and references
to functions: the target entity shall allow at least the exceptions allowed
by the source value in the assignment or initialization.
87. Exception specifications on function parameters
Section: 15.4 except.spec
Status: open Submitter: Steve Adamczyk Date: 25 Jan 1999An exception-specification shall appear only on a function
declarator in a function, pointer, reference or pointer to member declaration
or definition.
Does that mean in the top-level function declarator, or one at any level?
Can one, for example, specify an exception specification on a pointer-to-function
parameter of a function?
92. Should exception specifications be part of the type system?
Section: 15.4 except.spec
Status: open Submitter: Jonathan Schilling Date: 2 Feb 1999
37. When is uncaught_exception() true?
Section: 15.5.3 except.uncaught
Status: NAD Submitter: Daveed Vandevoorde Date: 10 Aug 1998
79. Alignment and placement new
Section: 18.4.1.3 lib.new.delete.placement
Status: open Submitter: Herb Sutter Date: 15 Dec 1998[Example: This can be useful for constructing
an object at a known address:
This example has potential alignment problems. One way to correct it would
be to change the definition of place to read:
81. Null pointers and C compatability
Section: D depr
Status: open Submitter: Steve Clamage Date: 27 Oct 1998
106. Creating references to references during template deduction/instantiation
Section: unknown
Status: open Submitter: Bjarne Stroustrup Date: unknown
Issue # | Title | Section |
1 | What if two using-declarations refer to the same function but the declarations introduce different default-arguments? | 8.3.6 |
2 | How can dependent names be used in member declarations that appear outside of the class template definition? | 14.6.4 |
3 | The template compilation model rules render some explicit specialization declarations not visible during instantiation | 14.7.3 |
4 | Does extern "C" affect the linkage of function names with internal linkage? | 7.5 |
5 | CV-qualifiers and type conversions | 8.5 |
6 | Should the optimization that allows a class object to alias another object also allow the case of a parameter in an inline function to alias its argument? | 12.8 |
7 | Can a class with a private virtual base class be derived from? | 11.2 |
8 | Access to template arguments used in a function return type and in the nested name specifier | 11 |
9 | Clarification of access to base class members | 11.2 |
10 | Can a nested class access its own class name as a qualified name if it is a private member of the enclosing class? | 11.8 |
11 | How do the keywords typename/template interact with using-declarations? | 7.3.3 |
12 | Default arguments on different declarations for the same function and the Koenig lookup | 3.4.2 |
13 | extern "C" for Parameters of Function Templates | 7.5 |
14 | extern "C" functions and declarations in different namespaces | 7.5 |
15 | Default arguments for parameters of function templates | 8.3.6 |
16 | Access to members of indirect private base classes | 11.2 |
17 | Footnote 98 should discuss the naming class when describing members that can be accessed from friends | 11.2 |
18 | f(TYPE) where TYPE is void should be allowed | 8.3.5 |
19 | Clarify protected member access | 11.5 |
20 | Some clarifications needed for 12.8 para 15 | 12.8 |
21 | Can a default argument for a template argument appear in a friend declaration? | 14.6.4 |
23 | Some questions regarding partial ordering of function templates | 14.5.5.2 |
24 | Typo in example 14.7.3 para 8 | 14.7.3 |
26 | Copy constructors and default arguments | 12.8 |
27 | Overload ambiguities for builtin ?: prototypes | 13.6 |
28 | 'exit', 'signal' and static object destruction | 3.6.3 |
29 | Linkage of locally declared functions | 7.5 |
31 | Looking up new/delete | 5.3.4 |
34 | Argument dependent lookup and points of instantiation | 14.7.1 |
36 | Using-declarations in multiple-declaration contexts | 7.3.3 |
37 | When is uncaught_exception() true? | 15.5.3 |
38 | Explicit template arguments and operator functions | 14.2 |
39 | Conflicting amgibuity rules | 10.2 |
40 | Syntax of declarator-id | 8.3 |
42 | Redefining names from base classes | 3.3.6 |
44 | Member specializations | 14.7.3 |
45 | Access to nested classes | 11.8 |
46 | Explicit instantiation of member templates | 14.7.2 |
47 | Template friend issues | 14.5.3 |
50 | Converting pointer to incomplete type to same type | 3.2 |
51 | Overloading and user-defined conversions | 13.3.3 |
52 | Non-static members, member selection and access checking | 5.2.5 |
53 | Lvalue-to-rvalue conversion before certain static_casts | 5.2.9 |
54 | Static_cast from private base to derived class | 5.2.9 |
55 | Adding/subtracting pointer and enumeration value | 5.7 |
56 | Redeclaring typedefs within classes | 7.1.3 |
57 | Empty unions | 9.5 |
58 | Signedness of bit fields of enum type | 9.6 |
59 | Clarification of overloading and UDC to reference type | 13.3.1.4 |
60 | Reference binding and valid conversion sequences | 13.3.3.1.4 |
61 | Address of static member function "&p->f" | 13.6 |
62 | Unnamed members of classes used as type parameters | 14.3.1 |
63 | Class instantiation from pointer conversion to void*, null and self | 14.7.1 |
64 | Partial ordering to disambiguate explicit specialization | 14.7.3 |
66 | Visibility of default args vs overloads added after using-declaration | 8.3.6 |
67 | Evaluation of left side of object-expression | 9.4 |
68 | Grammar does not allow "friend class A<int>;" | 7.1.5.3 |
69 | Storage class specifiers on template declarations | 7.1.1 |
70 | Is an array bound a nondeduced context? | 14.8.2.4 |
71 | Incorrect cross reference | 5 |
72 | Linkage and storage class specifiers for templates | 14 |
73 | Pointer equality | 5.10 |
74 | Enumeration value in direct-new-declarator | 5.3.4 |
75 | In-class initialized members must be const | 9.2 |
76 | Are const volatile variables considered "constant expressions"? | 7.1.5.1 |
77 | The definition of friend does not allow nested classes to be friends | 11.4 |
78 | Section 8.5 paragraph 9 should state it only applies to non-static objects | 8.5 |
79 | Alignment and placement new | 18.4.1.3 |
80 | Class members with same name as class | 9.2 |
81 | Null pointers and C compatability | D |
82 | Definition of "using" a constant expression | 3.2 |
83 | Overloading and deprecated conversion of string literal | 13.3.3.2 |
84 | Overloading and conversion loophole used by auto_ptr | 13.3.3.1 |
85 | Redeclaration of member class | 9.1 |
86 | Lifetime of temporaries in query expressions | 12.2 |
87 | Exception specifications on function parameters | 15.4 |
88 | Specialization of member constant templates | 14.7.3 |
89 | Object lifetime does not account for reference rebinding | 3.8 |
90 | Should the enclosing class be an "associated class" too? | 3.4.2 |
91 | A union's associated types should include the union itself | 3.4.2 |
92 | Should exception specifications be part of the type system? | 15.4 |
93 | Missing word in 3.8 [basic.life] paragraph 2 | 3.8 |
94 | Inconsistencies in the descriptions of constant expressions | 5.19 |
95 | Elaborated type specifiers referencing names declared in friend decls | 7.3.1.2 |
96 | Syntactic disambiguation using the template keyword | 14.2 |
97 | Use of bool constants in integral constant expressions | 5.19 |
98 | Branching into try block via switch label | 15 |
99 | Partial ordering, references and cv-qualifiers | 14.8.2.1 |
100 | Clarify why string literals are not allowed as template arguments | 14.3.2 |
101 | Redeclaration of extern "C" names via using-declarations | 7.3.3 |
102 | Operator lookup rules do not work well with parts of the library | 13.3.1.2 |
103 | Is it extended-namespace-definition or extension-namespace-definition ? | 7.3.4 |
104 | Destroying the exception temp when no handler is found | 15.1 |
105 | Meaning of "template function" | 14 |
106 | Creating references to references during template deduction/instantiation | unknown |
107 | Linkage of operator functions | 7.5 |
108 | Are classes nested in templates dependent? | 14.6.2.1 |
109 | Allowing ::template in using-declarations | 7.3.3 |
Issue # | Title | Section |
22 | Template parameter with a default argument that refers to itself | 14.6.4 |
25 | Exception specifications and pointers to members | 15.4 |
30 | Valid uses of '::template' | 14.2 |
32 | Clarification of explicit instantiation of non-exported templates | 14 |
33 | Argument dependent lookup and overloaded functions | 3.4.2 |
35 | Definition of default-initialization | 8.5 |
41 | Clarification of lookup of names after declarator-id | 3.4.1 |
43 | Copying base classes (PODs) using memcpy | 3.9 |
48 | Definitions of unused static members | 9.4.2 |
49 | Restriction on non-type, non-value template arguments | 14.1 |
65 | Typo in default argument example | 8.3.6 |
Section | Issue # | Title |
3.2 | 50 | Converting pointer to incomplete type to same type |
3.2 | 82 | Definition of "using" a constant expression |
3.3.6 | 42 | Redefining names from base classes |
3.4.2 | 12 | Default arguments on different declarations for the same function and the Koenig lookup |
3.4.2 | 90 | Should the enclosing class be an "associated class" too? |
3.4.2 | 91 | A union's associated types should include the union itself |
3.6.3 | 28 | 'exit', 'signal' and static object destruction |
3.8 | 89 | Object lifetime does not account for reference rebinding |
3.8 | 93 | Missing word in 3.8 [basic.life] paragraph 2 |
5 | 71 | Incorrect cross reference |
5.2.5 | 52 | Non-static members, member selection and access checking |
5.2.9 | 53 | Lvalue-to-rvalue conversion before certain static_casts |
5.2.9 | 54 | Static_cast from private base to derived class |
5.3.4 | 31 | Looking up new/delete |
5.3.4 | 74 | Enumeration value in direct-new-declarator |
5.7 | 55 | Adding/subtracting pointer and enumeration value |
5.10 | 73 | Pointer equality |
5.19 | 94 | Inconsistencies in the descriptions of constant expressions |
5.19 | 97 | Use of bool constants in integral constant expressions |
7.1.1 | 69 | Storage class specifiers on template declarations |
7.1.3 | 56 | Redeclaring typedefs within classes |
7.1.5.1 | 76 | Are const volatile variables considered "constant expressions"? |
7.1.5.3 | 68 | Grammar does not allow "friend class A<int>;" |
7.3.1.2 | 95 | Elaborated type specifiers referencing names declared in friend decls |
7.3.3 | 11 | How do the keywords typename/template interact with using-declarations? |
7.3.3 | 36 | Using-declarations in multiple-declaration contexts |
7.3.3 | 101 | Redeclaration of extern "C" names via using-declarations |
7.3.3 | 109 | Allowing ::template in using-declarations |
7.3.4 | 103 | Is it extended-namespace-definition or extension-namespace-definition ? |
7.5 | 4 | Does extern "C" affect the linkage of function names with internal linkage? |
7.5 | 13 | extern "C" for Parameters of Function Templates |
7.5 | 14 | extern "C" functions and declarations in different namespaces |
7.5 | 29 | Linkage of locally declared functions |
7.5 | 107 | Linkage of operator functions |
8.3 | 40 | Syntax of declarator-id |
8.3.5 | 18 | f(TYPE) where TYPE is void should be allowed |
8.3.6 | 1 | What if two using-declarations refer to the same function but the declarations introduce different default-arguments? |
8.3.6 | 15 | Default arguments for parameters of function templates |
8.3.6 | 66 | Visibility of default args vs overloads added after using-declaration |
8.5 | 5 | CV-qualifiers and type conversions |
8.5 | 78 | Section 8.5 paragraph 9 should state it only applies to non-static objects |
9.1 | 85 | Redeclaration of member class |
9.2 | 75 | In-class initialized members must be const |
9.2 | 80 | Class members with same name as class |
9.4 | 67 | Evaluation of left side of object-expression |
9.5 | 57 | Empty unions |
9.6 | 58 | Signedness of bit fields of enum type |
10.2 | 39 | Conflicting amgibuity rules |
11 | 8 | Access to template arguments used in a function return type and in the nested name specifier |
11.2 | 7 | Can a class with a private virtual base class be derived from? |
11.2 | 9 | Clarification of access to base class members |
11.2 | 16 | Access to members of indirect private base classes |
11.2 | 17 | Footnote 98 should discuss the naming class when describing members that can be accessed from friends |
11.4 | 77 | The definition of friend does not allow nested classes to be friends |
11.5 | 19 | Clarify protected member access |
11.8 | 10 | Can a nested class access its own class name as a qualified name if it is a private member of the enclosing class? |
11.8 | 45 | Access to nested classes |
12.2 | 86 | Lifetime of temporaries in query expressions |
12.8 | 6 | Should the optimization that allows a class object to alias another object also allow the case of a parameter in an inline function to alias its argument? |
12.8 | 20 | Some clarifications needed for 12.8 para 15 |
12.8 | 26 | Copy constructors and default arguments |
13.3.1.2 | 102 | Operator lookup rules do not work well with parts of the library |
13.3.1.4 | 59 | Clarification of overloading and UDC to reference type |
13.3.3 | 51 | Overloading and user-defined conversions |
13.3.3.1 | 84 | Overloading and conversion loophole used by auto_ptr |
13.3.3.1.4 | 60 | Reference binding and valid conversion sequences |
13.3.3.2 | 83 | Overloading and deprecated conversion of string literal |
13.6 | 27 | Overload ambiguities for builtin ?: prototypes |
13.6 | 61 | Address of static member function "&p->f" |
14 | 72 | Linkage and storage class specifiers for templates |
14 | 105 | Meaning of "template function" |
14.2 | 38 | Explicit template arguments and operator functions |
14.2 | 96 | Syntactic disambiguation using the template keyword |
14.3.1 | 62 | Unnamed members of classes used as type parameters |
14.3.2 | 100 | Clarify why string literals are not allowed as template arguments |
14.5.3 | 47 | Template friend issues |
14.5.5.2 | 23 | Some questions regarding partial ordering of function templates |
14.6.2.1 | 108 | Are classes nested in templates dependent? |
14.6.4 | 2 | How can dependent names be used in member declarations that appear outside of the class template definition? |
14.6.4 | 21 | Can a default argument for a template argument appear in a friend declaration? |
14.7.1 | 34 | Argument dependent lookup and points of instantiation |
14.7.1 | 63 | Class instantiation from pointer conversion to void*, null and self |
14.7.2 | 46 | Explicit instantiation of member templates |
14.7.3 | 3 | The template compilation model rules render some explicit specialization declarations not visible during instantiation |
14.7.3 | 24 | Typo in example 14.7.3 para 8 |
14.7.3 | 44 | Member specializations |
14.7.3 | 64 | Partial ordering to disambiguate explicit specialization |
14.7.3 | 88 | Specialization of member constant templates |
14.8.2.1 | 99 | Partial ordering, references and cv-qualifiers |
14.8.2.4 | 70 | Is an array bound a nondeduced context? |
15 | 98 | Branching into try block via switch label |
15.1 | 104 | Destroying the exception temp when no handler is found |
15.4 | 87 | Exception specifications on function parameters |
15.4 | 92 | Should exception specifications be part of the type system? |
15.5.3 | 37 | When is uncaught_exception() true? |
18.4.1.3 | 79 | Alignment and placement new |
D | 81 | Null pointers and C compatability |
unknown | 106 | Creating references to references during template deduction/instantiation |
Section | Issue # | Title |
3.4.1 | 41 | Clarification of lookup of names after declarator-id |
3.4.2 | 33 | Argument dependent lookup and overloaded functions |
3.9 | 43 | Copying base classes (PODs) using memcpy |
8.3.6 | 65 | Typo in default argument example |
8.5 | 35 | Definition of default-initialization |
9.4.2 | 48 | Definitions of unused static members |
14 | 32 | Clarification of explicit instantiation of non-exported templates |
14.1 | 49 | Restriction on non-type, non-value template arguments |
14.2 | 30 | Valid uses of '::template' |
14.6.4 | 22 | Template parameter with a default argument that refers to itself |
15.4 | 25 | Exception specifications and pointers to members |