Document number:
|
J16/98-0035 |
WG21 N1178 | |
Date:
|
24 October 1998 |
Project:
|
Programming Language C++ |
Reply to:
|
Bill Gibbons |
bill@gibbons.org |
Also see Table of Contents - Open Issues, Table of Contents - Closed Issues and Index by Section Number
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 From message-author-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.
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.
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 |
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 |
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 |
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 |
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.1 |
22 | Template parameter with a default argument that refers to itself | 14.1 |
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 |
25 | Exception specifications and pointers to members | 15.4 |
28 | 'exit', 'signal' and static object destruction | 3.6.3 |
29 | Linkage of locally declared functions | 7.5 |
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 |
36 | Using-declarations in multiple-declaration contexts | 7.3.3 |
38 | Explicit template arguments and operator functions | 14.2 |
39 | Conflicting amgibuity rules | 10.2 |
40 | Syntax of declarator-id | 8.3 |
41 | Clarification of lookup of names after declarator-id | 3.4.1 |
42 | Redefining names from base classes | 3.3.6 |
43 | Copying base classes (PODs) using memcpy | 3.9 |
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 |
48 | Definitions of unused static members | 9.4.2 |
49 | Restriction on non-type, non-value template arguments | 14.1 |
50 | Converting pointer to incomplete type to same type | 3.2 |
51 | Overloading and user-defined conversions | 13.3.3 |
52 | 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.4 |
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 |
65 | Typo in default argument example | 8.3.6 |
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 |
Issue # | Title | Section |
3 | The template compilation model rules render some explicit specialization declarations not visible during instantiation | 14.7.3 |
7 | Can a class with a private virtual base class be derived from? | 11.2 |
15 | Default arguments for parameters of function templates | 8.3.6 |
18 | f(TYPE) where TYPE is void should be allowed | 8.3.5 |
26 | Copy constructors and default arguments | 12.8 |
27 | Overload ambiguities for builtin ?: prototypes | 13.6 |
31 | Looking up new/delete | 5.3.4 |
34 | Argument dependent lookup and points of instantiation | 14.7.1 |
37 | When is uncaught_exception() true? | 15.5.3 |
Section | Issue # | Title |
3.2 | 50 | Converting pointer to incomplete type to same type |
3.3.6 | 42 | Redefining names from base classes |
3.4 | 41 | Clarification of lookup of names after declarator-id |
3.4.2 | 12 | Default arguments on different declarations for the same function and the koenig lookup |
3.4.2 | 33 | Argument dependent lookup and overloaded functions |
3.6.3 | 28 | 'exit', 'signal' and static object destruction |
3.9 | 43 | Copying base classes (PODs) using memcpy |
5.2.5 | 52 | 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.7 | 55 | Adding/subtracting pointer and enumeration value |
7.1.1 | 69 | Storage class specifiers on template declarations |
7.1.5.3 | 68 | Grammar does not allow "friend class A<int>;" |
7.1.3 | 56 | Redeclaring typedefs within classes |
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.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 |
8.3 | 40 | Syntax of declarator-id |
8.3.6 | 1 | What if two using-declarations refer to the same function but the declarations introduce different default-arguments? |
8.3.6 | 65 | Typo in default argument example |
8.3.6 | 66 | Visibility of default args vs overloads added after using-declaration |
8.5 | 5 | CV-qualifiers and type conversions |
8.5 | 35 | Definition of default-initialization |
9.4 | 67 | Evaluation of left side of object-expression |
9.4.2 | 48 | Definitions of unused static members |
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 | 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.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.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 |
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.4 | 60 | Reference binding and valid conversion sequences |
13.4 | 61 | Address of static member function "&p->f |
14 | 32 | Clarification of explicit instantiation of non-exported templates |
14.1 | 49 | Restriction on non-type, non-value template arguments |
14.1 | 21 | Can a default argument for a template argument appear in a friend declaration? |
14.1 | 22 | Template parameter with a default argument that refers to itself |
14.2 | 30 | Valid uses of '::template' |
14.2 | 38 | Explicit template arguments and operator functions |
14.3.1 | 62 | Unnamed members of classes used as type parameters |
14.5.5.2 | 23 | Some questions regarding partial ordering of function templates |
14.5.3 | 47 | Template friend issues |
14.6.4 | 2 | How can dependent names be used in member declarations that appear outside of the class template definition? |
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 | 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.8.2.4 | 70 | Is an array bound a nondeduced context? |
15.4 | 25 | Exception specifications and pointers to members |
Section | Issue # | Title |
5.3.4 | 31 | Looking up new/delete |
8.3.5 | 18 | f(TYPE) where TYPE is void should be allowed |
8.3.6 | 15 | default arguments for parameters of function templates |
11.2 | 7 | Can a class with a private virtual base class be derived from? |
12.8 | 26 | Copy constructors and default arguments |
13.6 | 27 | Overload ambiguities for builtin ?: prototypes |
14.7.1 | 34 | Argument dependent lookup and points of instantiation |
14.7.3 | 3 | The template compilation model rules render some explicit specialization declarations not visible during instantiation |
15.5.3 | 37 | When is uncaught_exception() true? |
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).
From reflector message core-7848
Consider this code:
The idea is that the enumerator "next" in each class is the next available value for enumerators in further derived classes.struct Base { enum { a, b, c, next }; }; struct Derived : public Base { enum { d = Base::next, e, f, next }; };
If we had written
I think we would run afoul of 3.3.6 Class scope:enum { d = next, e, f, next };
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 ..."?
Tentative Resolution:
The term "re-evaluated" was not well defined. Define it as "looked up again in the same manner in which it was originally looked up but considering names declared later in the class (in addition to names declared earlier, as is usually done)". We need a proposal for the actual wording change.
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."
Tentative Resolution:
Change basic.lookup.unqual paragraph 6 and 8 (footnotes 26 and 29) from
... following the function declarator ...to
... following the function declarator-id ...Also add normative text (proposal needed) making this clear. May need work in clause 7 as well.
(Previously numbered 915.)
Given the following test case:
enum E { e1, e2, e3 }; void f(int, E e = e1); void f(E, E e = e1); void g() { void f(long, E e = e2); f(1); // calls ::f(int, E) f(e1); // ? }First note that Koenig lookup breaks the concept of hiding functions through local extern declarations as illustrated by the call `f(1)'. Should the WP show this as an example?
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?
Tentative Resolution:
In basic.lookup.koenig pagagraph 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.
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?
Tentative Resolution:
In basic.lookup.koenig paragraph 2, add the following text after the bullet list:
The set of namespaces associated with an argument which is the name or address of a set of overloaded functions, including function templates, is the union of the sets of namespaces associated with the individual functions and/or function templates.
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 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.
Tentative Resolution:
Change basic.types paragraph 2 from
For any complete POD object type T, ...to
For any object (other than a base class subobject) of complete POD type T, ...Change basic.types paragraph 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, ...
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.
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.
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.
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.
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?]
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.
Can a typedef redeclaration be done within a class?
class X { typedef int I; typedef int I; };See also 9.2/2.
I can't find the answer to the following in the standard. Does anybody have a reference?
The syntax for elaborated type specifier is
elaborated-type-specifier:If an elaborated-type-specifier is the sole constituent of a declaration, the declaration is ill-formed unless it is an explicit specialization (temp.expl.spec), an explicit instantiation (temp.explicit) or it has one of the following forms:
class-key ::opt nested-name-specifieropt identifier
enum ::opt nested-name-specifieropt identifier
typename ::opt nested-name-specifier identifier
typename ::opt nested-name-specifier templateopt template-id
class-key identifier:Which does not allow the production
friend class-key identifier ;
friend class-key :: identifier ;
friend class-key nested-name-specifier identifier ;
class foo<int> // foo is a template
On the other hand, a friend declaration seems to require this production,
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:
template<class T> class task;Is there some special dispensation somewhere to allow the syntax in this context? Is there something I've missed about elaborated-type-specifier? Is it just another bug in the standard?
template<class T> task<T>* preempt(task<T>*);template<class T> class task {
// ...
friend void next_time();
friend void process(task<T>*);
friend task<T>* preempt<T>(task<T>*);
template<class C> friend int func(C);friend class task<int>;
template<class P> friend class frd;
// ...
};
(Previously numbered 914.)
Issue 1:
The working paper is not clear about how the typename/template keywords interact with using-declarations:
template<class T> struct A { typedef int X; }; template<class T> void f() { typename A<T>::X a; // OK using typename A<T>::X; // OK typename X b; // ill-formed; X must be qualified X c; // is this OK? }When the rules for typename and the similar use of template were decided, we chose to require them at every use of the dependent name - that is, using them once with a name does not "declare" the name to be a type with regard to any subsequent use of the name. The way to avoid writing typename at every use is to declare a typedef; then the typedef name itself is known to be a type. For using-declarations, we decided that they do not introduce new declarations but rather are aliases for existing declarations, like symbolic links. This makes it unclear whether the declaration "X c;" above should be well-formed, because there is no new name declared so there is no declaration with a "this is a type" attribute. (The same problem would occur with the template keyword when a member template of a dependent class is used). I think these are the main options:
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:
template<class T> struct A { struct X { }; }; template<class T> void g() { using typename A<T>::X; X c; // if this is OK, then X by itself is a type int X; // is this OK? }When "g" is instantiated, the two declarations of X are compatible (7.3.3/10). But there is no way to know this when the definition of "g" is compiled. I think this case should be ill-formed under the first option. (It cannot happen under the second option.) If the second option is adopted:
template<class T> struct A { struct X { }; }; template<class T> void g() { using A<T>::X; int X; // is this OK? }Again, the instantiation would work but there is no way to know that in the template definition. I think this case should be ill-formed under the second option. (It would already be ill-formed under the first option.)
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:
However, if "using A::i;" is really a declaration, and not a definition, it is far from clear that repeating it should be an error in either context. Consider:namespace A { int i; } namespace A1 { using A::i; using A::i; // OK: double declaration } void f() { using A::i; using A::i; // error: double declaration }
Surely the definition of f should be analogous tonamespace A { int i; void g(); } void f() { using A::g; using A::g; }
which is well-formed because "void g();" is a declaration and not a definition.void f() { void g(); void g(); }
Indeed, if the double using-declaration for A::i is prohibited in f, why should it be allowed in namespace A1?
Tentative Resolution:
Any using-declaration may be repeated in any scope. This needs wording.
(Previously numbered 864.)
7.5 para 6 says the following:
extern "C" { static void f(int) {} static void f(float) {} };Can a function with internal linkage "have C linkage" at all (assuming that phrase means "has extern "C" linkage"), for how can a function be extern "C" if it's not extern? The function type can have extern "C" linkage -- but I think that's independent of the linkage of the function name. It should be perfectly reasonable to say, in the example above, that extern "C" applies only to the types of f(int) and f(float), not to the function names, and that the rule in 7.5 para 6 doesn't apply. Mike's proposed resolution: The extern "C" linkage specification applies only to the type of functions with internal linkage, and therefore some of the rules that have to do with name overloading don't apply.
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 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?
extern "C" void f(int); void g(char);
template <class T> struct A { A(void (*fp)(T)); };
A<char> a1(g); // okay A<int> a2(f); // errorAnother variant of the same problem is:
extern "C" void f(int); void g(char);
template <class T> void h( void (*fp)(T) ); int main() { h(g); // okay h(f); // error }
Somehow permit a language linkage to be specified as part of a function parameter declaration. i.e.
template <class T> struct A { A( extern "C" void (*fp)(T) ); };
template <class T> void h( extern "C" void (*fp)(T) );Proposed resolution: (Bill Gibbons)
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:
void f( void (*pf)(int) c_linkage );instead of the suggested:
void f( extern "C" void (*pf)(int) );I would like to keep calling convention on the "next round" issues list, including the alternative of using function qualifiers.
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
7.5 para 6 says the following:
extern "C" int f(void); namespace A { extern "C" int f(void); }; using namespace A; int i = f(); // Ok because only one function f() or // ill-formedFor name lookup, both declarations of f are visible and overloading cannot distinguish between them. Has the compiler to check that these functions are really the same function or is the program in error?
Rationale:
Not a defect; these are the same function for all purposes.
Issue 2
A similar question may arise with typedefs:
// vendor A typedef unsigned int size_t; // vendor B namespace std { typedef unsigned int size_t; } using namespace std; size_t something(); // error?Is this valid because the typedef size_t refers to the same type in both namespaces?
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. Needs to be drafted.
From reflector message core-7714
Consider the following:
extern "C" void foo() { extern void bar(); bar(); }Is does "bar()" have "C" language linkage?
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,
declaration:and 8.4p1:
function-definition
function-definition:At least that's how I'd read it.
decl-specifier-seqopt declarator ctor-initializeropt function-body
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:
extern "C" void foo();
void foo() { extern void bar(); bar(); }I think the ARM wording could possibly be interpreted such that bar() has "C" linkage in my example, but not the DIS wording.
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-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.
Tentative Resolution:
As above, but it needs better wording. Mike Miller will supply
wording.
(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, -- they shall all refer to the same entity, or all refer to functions ...8.3.6 para 9 says:
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:
namespace A { extern "C" void f(int = 5); } namespace B { extern "C" void f(int = 7); } using A::f; using B::f; f(); // ???Tentative Resolution:
If the function selected by overload is represented by more than one function declaration in the set of overloaded function declarations which was considered, and a parameter for which a default argument is used has a default argument definition in more than one of these declarations, the program is ill-formed even if the default argument definitions are identical. David Vandervoorde will provide additional drafting.
(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?
template <class T> struct B { template <class U> inline void f(U); }; template <class T> template <class U> inline void B<T>::f(U = int) {} // adds default arguments // is this well-formed? void g() { B<int> b; b.f(); }If this is ill-formed, chapter 14 should mention this.
Rationale:
This is sufficiently clear in the standard. Allowing additional default arguments would be an extension.
In section 8.3.6 paragraph 5 the last sentence before the example code says:
... g will be called with the value f(1).It should say:
... 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:
struct A { A(A&); }; struct B : A { }; struct C { operator B&(); }; C c; const A a = c; // allowed?The temporary created with the conversion function is an lvalue of type B. If the temporary must have the cv-qualifiers of the destination type (i.e. const) then the copy-constructor for A cannot be called to create the object of type A from the lvalue of type const B. If the temporary has the cv-qualifiers of the result type of the conversion function, then the copy-constructor for A can be called to create the object of type A from the lvalue of type const B. This last outcome seems more appropriate.
Tentative Resolution:
As above. Steve Adamczyk will draft the clarification.
From reflector message core-7780
Given:
Once upon a time, we went through a fairly protracted discussion to ensure that S1().x would be guaranteed to be 0. Note that if we declarestruct S1 { int x; }; struct S2 { int x; double y; }; struct S3 { int x; double y; string s; };
there is no guarantee of the value of s1.x, and that is intentional. But S1().x is different, because S1() is an rvalue, and unless all of its members are defined, the effect of copying it is undefined.void f() { S1 s1; // ... }
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.
Tentative Resoution:
As proposed. Basically: when a synthesized default constructor is called to perform default initialization, it default-initializes its base class subobjects and member subobjects. Andy Koenig will draft better wording.
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 &&.
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:
struct A { static const int size = 10; int array[size]; }; int main() { A a; return 0; }However, 9.2.4/4 says:
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_).Tentative Resolution:
As proposed. The list of contexts where only the value is needed should also include case labels. Bill Gibbons will draft wording.
There doesn't seem to be a prohibition in 9.5 against a declaration like
union { int : 0; } x;Should that be valid? If so, 8.5/5 third bullet, which deals with default-initialization of unions, should say that no initialization is done if there are no data members.
What about:
union { } x; static union { };If the first example is well-formed, should either or both of these cases be well-formed as well?
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:
This is a name lookup ambiguity because of 10.2p2:struct A { int x(int); }; struct B: A { using A::x; float x(float); }; int f(B* b) { b->x(3); // ambiguous }
... 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:
class A { class A1{}; static void func(A1, int); static void func(float, int); static const int garbconst = 3; public: template < class T, int i, void (*f)(T, int) > class int_temp {}; template<> class int_temp<A1, 5, func> { void func1() }; friend int_temp<A1, 5, func>::func1(); int_temp<A1, 5, func>* func2(); }; A::int_temp<A::A1, A::garbconst + 2, &A::func>* A::func2() {...}ISSUE 1:
In clause 11 paragraph 5 we have:
A::int_temp A::A1 A::garbconst (part of an expression) A::func (after overloading is done)I suspect that member templates were not really considered when this was written, and that it might have been written rather differently if they had been. Note that access to the template arguments is only legal because the class has been declared a friend, which is probably not what most programmers would expect.
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.)
class Foo { public: Foo() {} ~Foo() {} }; class A : virtual private Foo { public: A() {} ~A() {} }; class Bar : public A { public: Bar() {} ~Bar() {} };~Bar() calls ~Foo(), which is ill-formed due to access violation, right? (Bar's constructor has the same problem since it needs to call Foo's constructor.) There seems to be some disagreement among compilers. Sun, IBM and g++ reject the testcase, EDG and HP accept it. Perhaps this case should be clarified by a note in the draft.
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?
class D; class B { protected: int b1; friend void foo( D* pd ); }; class D : protected B { }; void foo( D* pd ) { if ( pd->b1 > 0 ); // Is 'b1' accessible? }Can you access the protected member b1 of B in foo? Can you convert a D* to a B* in foo?
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 will write a paper on issues 9, 16, 17 and 19.
(Previously numbered 924.)
The text in 11.2 para 4 does not seem to handle the following cases:
class D; class B { private: int i; friend class D; }; class C : private B { }; class D : private C { void f() { B::i; //1: well-formed? i; //2: well-formed? } };The member i is not a member of D and cannot be accessed in the scope of D. What is the naming class of the member i on line //1 and line //2?
Tom Wilcox will write a paper on issues 9, 16, 17 and 19.
(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 will write a paper on issues 9, 16, 17 and 19.
(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 will write a paper on issues 9, 16, 17 and 19.
(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?
class D { class E { static E* m; }; }; D::E* D::E::m = 1; // ill-formedThis is because the nested class does not have access to the member E in D. 11 paragraph 5 says that access to D::E is checked with member access to class E, but unfortunately that doesn't give access to D::E. 11 paragraph 6 covers the access for D::E::m, but it doesn't affect the D::E access. Are there any implementations that are standard compliant that support this? ---- Here is another example:
class C { class B { C::B *t; //2 error, C::B is inaccessible }; };This causes trouble for member functions declared outside of the class member list. For example:
class C { class B { B& operator= (const B&); }; }; C::B& C::B::operator= (const B&) { } //3If the return type (i.e. C::B) is access checked in the scope of class B (as implied by 11 para 5) as a qualified name, then the return type is an error just like referring to C::B in the member list of class B above (i.e. //2) is ill-formed.
This issue depends on the outcome of Core Issue 45.
From reflector message core-7855
Example:
How legal/illegal is this? Paragraphs that seem to apply here are:#include <iostream.h> class C { // entire body is private struct Parent { Parent() { cout << "C::Parent::Parent()\n"; } }; struct Derived : Parent { Derived() { cout << "C::Derived::Derived()\n"; } }; Derived d; }; int main() { C c; // Prints message from both nested classes return 0; }
[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.
(Previously numbered 876b.)
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?
Tentative Resolution:
This change is supported if additional analysis shows it to be safe. Bjarne Stroustrup will write a paper proposing the change.
(Previously numbered 931.)
Issue 1
12.8 para 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:*
Thing f() { Thing t; return t; } Thing t2 = f();Here t does not need to be copied when returning from f. The return value of f may be constructed directly into the object t2.
* 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.
From reflector message core-7647
The working paper is quite explicit about
struct X { X(X, X const& = X()); };being illegal (because of the chicken & egg problem wrt copying.)
Shouldn't it be as explicit about the following?
struct Y { Y(Y const&, Y = Y()); };Rationale:
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.
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.
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.
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-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:
bool test; Integer a, b; test ? a : b;What builtin do we use? The candidates are
operator ?:(bool, const Integer &, const Integer &) operator ?:(bool, Integer, Integer)which are both perfect matches.
(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.
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".
Tentative Resolution:
As proposed, with the additional correction that only the specialization which is instantiated must be defined. Change temp paragraph 8 from
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 requiredto
A template, explicit specialization or partial specialization which is not exported and not 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
The example in temp.dep.res paragraph 8 is:
template<int* a> struct R { /*...*/ }; int* p; R<p> w;There was a French comment was that this is an error, and there was general agreement with that.
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?
Tentative Resolution:
The example should be changed to:
template<int* a> struct R { /*...*/ }; int* p; R<&p> w;Text should be added to restrict template arguments matching template parameters of pointer or pointer to member type; such an argument must either have the form "& name" or "name", where name specifies an object or function with external linkage and where the form without "&" is allowed only when there is an implicit conversion from an array or function type to a pointer type. This needs drafting.
(Previously numbered 932.)
14.1 para 10 says:
The 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?
i.e.
template<class T1, class T2 = int> class A; class B { friend<class T1 = int, class T2> class A; };Is this well-formed? If it is, should the WP say when the default argument for T1 is considered for instantiations of class A?
(Previously numbered 933.)
14.1 para 13 says:
The 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?
template<class U = U> class X { ... };Tentative Resolution:
Change temp.param paragraph 14 from:
A template-parameter cannot be used in preceding template-parameters 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..
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
X::template Yallowed? (It is required for dependent X where Y is a template-id, I believe, but it doesn't seem to be disallowed elsewhere.)
The question also holds for '.template' and '->template'.
Tentative Resolution:
The rules for the template keyword within a qualified name should be the same as those for the typename keyword. David Vandevoorde will draft proposed wording.
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:
From John Spicer:friend A::B operator + <>(char&);
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.
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.
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:
I hope we would all agree that this program is ill-formed, even if long and int have the same size.template <class T> struct A { friend int f() { return sizeof(T); } }; A<int> ai; A<long> ac;
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:
it is a redefinition (which is not allowed) and an ODR violation. And if you write:struct A_int { friend int f() { return sizeof(int); } }; struct A_long { friend int f() { return sizeof(long); } };
the corresponding non-template code would be:template <class T, class U> struct A { friend int f() { return sizeof(U); } }; A<int,float> ai; A<llong,float> ac;
then the two definitions of "f" are identical so there is no ODR violation, but it is still a redefinition. I think this is just an editorial clarification.struct A_int_float { friend int f() { return sizeof(float); } }; struct A_long { friend int_float f() { return sizeof(float); } };
Tentative Resolution:
As proposed above. This needs to be drafted.
(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:
template<class T> void f(T,int); template<class T> void f(T, T); void f(1,1);For the first function template, there is no type deduction for the second parameter. So the rules in this clause seem to imply that the second function template will be chosen.
Rationale:
This is not a defect; the standard unambiguously makes the above example ill-formed due to ambiguity.
(Previously numbered 737.)
template <class T> class Foo { public: typedef int Bar; Bar f(); }; template <class T> typename Foo<T>::Bar Foo<T>::f() { return 1;} --------------------In the class template definition, the declaration of the member function is interpreted as:
int Foo<T>::f();In the definition of the member function that appears outside of the class template, the return type is not known until the member function is instantiated. Must the return type of the member function be known when this out-of-line definition is seen (in which case the definition above is ill-formed)? Or is it OK to wait until the member function is instantiated to see if the type of the return type matches the return type in the class template definition (in which case the definition above is well-formed)?
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.
template <class T> class A { typedef int X; }; template <class T> class Foo { public: typedef int Bar; typedef typename A<T>::X X; Bar f(); Bar g1(); int g2(); X h(); X i(); int j(); }; // Declarations that are okay template <class T> typename Foo<T>::Bar Foo<T>::f() { return 1;} template <class T> typename Foo<T>::Bar Foo<T>::g1() { return 1;} template <class T> int Foo<T>::g2() { return 1;} template <class T> typename Foo<T>::X Foo<T>::h() { return 1;} // Declarations that are not okay template <class T> int Foo<T>::i() { return 1;} template <class T> typename Foo<T>::X Foo<T>::j() { return 1;}In general, if you can match the declarations up using only information from the template, then the declaration is valid.
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.
From reflector message core-7772
Does Koenig lookup create a point of instantiation for class types? I.e., if I say:
TT<int> *p; f(p);The namespaces and classes associated with p are those associated with the type pointed to, i.e., TT<int>. However, to determine those I need to know TT<int> bases and its friends, which requires instantiation.
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?
Since multiple "template<>" clauses are permitted in an explicit specialization, it might follow that multiple "template" keywords should also be permitted in an explicit instantiation. Are multiple "template" keywords are not allowed in an explicit instantiation? The grammer permits it, but the grammer permits lots of stuff far weirder than that. My opinion is that, in the absence of explicit wording permitting that kind of usage (as is present for explicit specializations) that such usage is not permitted for explicit instantiations.template <class T> struct A { template <class T2> void f(T2){} };template void A<int>::f(char); // okaytemplate template void A<int>::f(float); // ?
Tentative Resolution:
Only one template keyword should be allowed per explicit instantiation. The grammar does not have such a restriction. We need to draft a clarification.
(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
template<class T> struct A { }; export template<class T> void f(T) { A<T> a; }translation unit #2
template<class T> struct A { }; template<> struct A<int> { }; // not visible during instantiation template<class T> void f(T); void g() { f(1); }Rationale:
This issue was addressed in the FDIS and should have been closed.
(Previously numbered 935.)
14.7.3 para 8 has the following:
// explicit specialization of vector for vector<B> template<class T> class vector<B> { /* ... */ } -----------------This should be template<>
Tentative Resolution:
Change the following lines in the example in temp.expl.spec paragraph 8 from
// Explicit specialization of vector for vector<B> template<class T> class vector<B> { /* ... */ }to
// Explicit specialization of vector for vector<B> template<> class vector<B> { /* ... */ }
From reflector message core-7851
Some compilers reject the following:
on the basis of [temp.expl.spec] paragraph 2:struct A { template <int I> void f(); template <> void f<0>(); };
An 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.
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:
Change the text in temp.expl.spec paragraph 17 from
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 and that declaration shall be preceded by a template<> for each enclosing class template (of the member declaration) that is explicitly specialized.
Paragraph 12 should address partial ordering. It wasn't updated
when that
change was made and conflicts with 14.5.5.2/1.
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:
template <int I> class IntArr {};Can anybody shed some light on this?template <int I, int J>
void concat( int (&d)[I+J], const IntArr<I>& a, const IntArr<J>& b ) {}int testing()
{
IntArr<2> a;
IntArr<3> b;
int d[5];concat( d, a, b );
}
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:
...
(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.
Tentative Resolution:
Pointers to member functions should have the same restriction as pointers to functions with respect to exception specifications. Also, the sentence describing this restriction seems to refer to assigning to or initializing functions, which is not correct. Change the text in except.spec paragraph 3 from
Similarly, 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
Similarly, any function, pointer to function or pointer to member function assigned to, or initializing, a pointer to function or pointer to member function shall only allow exceptions that are allowed by the pointer to function or pointer to member function being assigned to or initialized.
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.