Document number:  J16/06-0067 = WG21 N1997
Date:  2006-04-22
Project:  Programming Language C++
Reference:  ISO/IEC IS 14882:2003
Reply to:  William M. Miller
 Edison Design Group, Inc.
 wmm@edg.com


C++ Standard Core Language Active Issues, Revision 41


This document contains the C++ core language issues on which the Committee (J16 + WG21) has not yet acted, that is, issues with status "Ready," "Review," "Drafting," and "Open."

This document is part of a group of related documents that together describe the issues that have been raised regarding the C++ Standard. The other documents in the group are:

The purpose of these documents is to record the disposition of issues which have come before the Core Language Working Group of the ANSI (J16) and ISO (WG21) C++ Standard Committee.

Issues represent potential defects in the ISO/IEC IS 14882:2003 document and corrected defects in the earlier ISO/IEC 14882:1998 document; they are not necessarily formal ISO Defect Reports (DRs). While some issues will eventually be elevated to DR status, others will be disposed of in other ways. (See Issue Status below.)

The most current public version of this document can be found at http://www.open-std.org/jtc1/sc22/wg21. Requests for further information about these documents should include the document number, reference ISO/IEC 14882:2003, and be submitted to the InterNational Committee for Information Technology Standards (INCITS), 1250 Eye Street NW, Suite 200, Washington, DC 20005, USA.

Information regarding how to obtain a copy of the C++ Standard, join the Standard Committee, or submit an issue can be found in the C++ FAQ at http://www.jamesd.demon.co.uk/csc/faq.html. Public discussion of the C++ Standard and related issues occurs on newsgroup comp.std.c++.


Revision History

Issue status

Issues progress through various statuses as the Core Language Working Group and, ultimately, the full J16 and WG21 committees deliberate and act. For ease of reference, issues are grouped in these documents by their status. Issues have one of the following statuses:

Open: The issue is new or the working group has not yet formed an opinion on the issue. If a Suggested Resolution is given, it reflects the opinion of the issue's submitter, not necessarily that of the working group or the Committee as a whole.

Drafting: Informal consensus has been reached in the working group and is described in rough terms in a Tentative Resolution, although precise wording for the change is not yet available.

Review: Exact wording of a Proposed Resolution is now available for an issue on which the working group previously reached informal consensus.

Ready: The working group 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 ratification as a proposed defect report.

DR: The full Committee has approved the item as a proposed defect report. The Proposed Resolution in an issue with this status reflects the best judgment of the Committee at this time regarding the action that will be taken to remedy the defect; however, the current wording of the Standard remains in effect until such time as a Technical Corrigendum or a revision of the Standard is issued by ISO.

TC1: A DR issue included in Technical Corrigendum 1. TC1 is a revision of the Standard issued in 2003.

WP: A DR issue whose resolution is reflected in the current Working Paper. The Working Paper is a draft for a future version of the Standard.

Dup: The issue is identical to or a subset of another issue, identified in a Rationale statement.

NAD: The working group has reached consensus that the issue is not a defect in the Standard. A Rationale statement describes the working group's reasoning.

Extension: The working group has reached consensus that the issue is not a defect in the Standard but is a request for an extension to the language. The working group expresses no opinion on the merits of an issue with this status; however, the issue will be maintained on the list for possible future consideration as an extension proposal.


Issues with "Ready" Status


505. Conditionally-supported behavior for unknown character escapes

Section: 2.13.2  lex.ccon     Status: ready     Submitter: Mike Miller     Date: 14 Apr 2005

The current wording of 2.13.2  lex.ccon paragraph 3 states,

If the character following a backslash is not one of those specified, the behavior is undefined.

Paper J16/04-0167=WG21 N1727 suggests that such character escapes be ill-formed. In discussions at the Lillehammer meeting, however, the CWG felt that the newly-approved category of conditionally-supported behavior would be more appropriate.

Proposed resolution (April, 2006):

Change the next-to-last sentence of 2.13.2  lex.ccon paragraph 3 from:

If the character following a backslash is not one of those specified, the behavior is undefined.

to:

Escape sequences in which the character following the backslash is not listed in Table 6 are conditionally-supported, with implementation-defined semantics.



514. Is the initializer for a namespace member in the scope of the namespace?

Section: 3.4.1  basic.lookup.unqual     Status: ready     Submitter: Mike Miller     Date: 24 Mar 2005

Is the following code well-formed?

    namespace N {
      int i;
      extern int j;
    }
    int N::j = i;

The question here is whether the lookup for i in the initializer of N::j finds the declaration in namespace N or not. Implementations differ on this question.

If N::j were a static data member of a class, the answer would be clear: both 3.4.1  basic.lookup.unqual paragraph 12 and 8.5  dcl.init paragraph 11 say that the initializer “is in the scope of the member's class.” There is no such provision for namespace members defined outside the namespace, however.

The reasoning given in 3.4.1  basic.lookup.unqual may be instructive:

A name used in the definition of a static data member of class X (9.4.2  class.static.data) (after the qualified-id of the static member) is looked up as if the name was used in a member function of X.

It is certainly the case that a name used in a function that is a member of a namespace is looked up in that namespace (3.4.1  basic.lookup.unqual paragraph 6), regardless of whether the definition is inside or outside that namespace. Initializers for namespace members should probably be looked up the same way.

Proposed resolution (April, 2006):

Add a new paragraph following 3.4.1  basic.lookup.unqual paragraph 12:

If a variable member of a namespace is defined outside of the scope of its namespace then any name used in the definition of the variable member (after the declarator-id) is looked up as if the definition of the variable member occurred in its namespace. [Example:

    namespace N {
      int i = 4;
      extern int j;
    }

    int i = 2;

    int N::j = i;	// N::j == 4

end example]




557. Does argument-dependent lookup cause template instantiation?

Section: 3.4.2  basic.lookup.argdep     Status: ready     Submitter: Mike Miller     Date: 8 February 2006

One might assume from 14.7.1  temp.inst paragraph 1 that argument-dependent lookup would require instantiation of any class template specializations used in argument types:

Unless a class template specialization has been explicitly instantiated (14.7.2  temp.explicit) or explicitly specialized (14.7.3  temp.expl.spec), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.

A complete class type is required to determine the associated classes and namespaces for the argument type (to determine the class's bases) and to determine the friend functions declared by the class, so the completeness of the class type certainly “affects the semantics of the program.”

This conclusion is reinforced by the second bullet of 3.4.2  basic.lookup.argdep paragraph 2:

A class template specialization is a class type, so the second bullet would appear to apply, requiring the specialization to be instantiated in order to determine its base classes.

However, bullet 8 of that paragraph deals explicitly with class template specializations:

Note that the class template specialization itself is not listed as an associated class, unlike other class types, and there is no mention of base classes. If bullet 8 were intended as a supplement to the treatment of class types in bullet 2, one would expect phrasing along the lines of, “In addition to the associated namespaces and classes for all class types...” or some such; instead, bullet 8 reads like a self-contained and complete specification.

If argument-dependent lookup does not cause implicit instantiation, however, examples like the following fail:

    template <typename T> class C {
        friend void f(C<T>*) { }
    };
    void g(C<int>* p) {
        f(p);    // found by ADL??
    }

Implementations differ in whether this example works or not.

Proposed resolution (April, 2006):

  1. Change bullet 2 of 3.4.2  basic.lookup.argdep paragraph 2 as indicated:

  2. Delete bullet 8 of 3.4.2  basic.lookup.argdep paragraph 2:




305. Name lookup in destructor call

Section: 3.4.5  basic.lookup.classref     Status: ready     Submitter: Mark Mitchell     Date: 19 May 2001

I believe this program is invalid:

    struct A {
    };

    struct C {
      struct A {};
      void f ();
    };

    void C::f () {
      ::A *a;
      a->~A ();
    }
The problem is that 3.4.5  basic.lookup.classref says that you have to look up A in both the context of the pointed-to-type (i.e., ::A), and in the context of the postfix-expression (i.e., the body of C::f), and that if the name is found in both places it must name the same type in both places.

The EDG front end does not issue an error about this program, though.

Am I reading the standardese incorrectly?

John Spicer: I think you are reading it correctly. I think I've been hoping that this would get changed. Unlike other dual lookup contexts, this is one in which the compiler already knows the right answer (the type must match that of the left hand of the -> operator). So I think that if either of the types found matches the one required, it should be sufficient. You can't say a->~::A(), which means you are forced to say a->::A::~A(), which disables the virtual mechanism. So you would have to do something like create a local typedef for the desired type.

See also issues 244, 399, and 466.

Proposed resolution (April, 2006):

  1. Remove the indicated text from 3.4.5  basic.lookup.classref paragraph 2:

    If the id-expression in a class member access (5.2.5  expr.ref) is an unqualified-id, and the type of the object expression is of a class type C (or of pointer to a class type C), the unqualified-id is looked up in the scope of class C...
  2. Change 3.4.5  basic.lookup.classref paragraph 3 as indicated:

    If the unqualified-id is ~type-name, the type-name is looked up in the context of the entire postfix-expression. and If the type T of the object expression is of a class type C (or of pointer to a class type C), the type-name is also looked up in the context of the entire postfix-expression and in the scope of class C. The type-name shall refer to a class-name. If type-name is found in both contexts, the name shall refer to the same class type. If the type of the object expression is of scalar type, the type-name is looked up in the scope of the complete postfix-expression. At least one of the lookups shall find a name that refers to (possibly cv-qualified) T. [Example:
        struct A { };
    
        struct B {
          struct A { };
          void f(::A* a);
        };
    
        void B::f(::A* a) {
          a->~A();  // OK, lookup in *a finds the injected-class-name
        }
    
    end example]

[Note: this change also resolves issue 414.]




414. Multiple types found on destructor lookup

Section: 3.4.5  basic.lookup.classref     Status: ready     Submitter: John Spicer     Date: 1 May 2003

By 3.4.5  basic.lookup.classref paragraph 3, the following is ill-formed because the two lookups of the destructor name (in the scope of the class of the object and in the surrounding context) find different Xs:

  struct X {};
  int main() {
    X x;
    struct X {};
    x.~X();  // Error?
  }

This is silly, because the compiler knows what the type has to be, and one of the things found matches that. The lookup should require only that one of the lookups finds the required class type.

Proposed resolution (April, 2005):

This issue is resolved by the resolution of issue 305.




521. Requirements for exceptions thrown by allocation functions

Section: 3.7.3.1  basic.stc.dynamic.allocation     Status: ready     Submitter: Alisdair Meredith     Date: 22 May 2005

According to 3.7.3.1  basic.stc.dynamic.allocation paragraph 3,

Any other allocation function that fails to allocate storage shall only indicate failure by throwing an exception of class std::bad_alloc (18.4.2.1  lib.bad.alloc) or a class derived from std::bad_alloc.

Shouldn't this statement have the usual requirements for an unambiguous and accessible base class?

Proposed resolution (April, 2006):

Change the last sentence of 3.7.3.1  basic.stc.dynamic.allocation paragraph 3 as indicated:

Any other allocation function that fails to allocate storage shall only indicate failure only by throwing an exception of class std::bad_alloc (18.4.2.1  lib.bad.alloc) or a class derived from std::bad_alloc a type that would match a handler (15.3  except.handle) of type std::bad_alloc (18.4.2.1  lib.bad.alloc).



480. Is a base of a virtual base also virtual?

Section: 4.11  conv.mem     Status: ready     Submitter: Mark Mitchell     Date: 18 Oct 2004

When the Standard refers to a virtual base class, it should be understood to include base classes of virtual bases. However, the Standard doesn't actually say this anywhere, so when 4.11  conv.mem (for example) forbids casting to a derived class member pointer from a virtual base class member pointer, it could be read as meaning:

  struct B {};
  struct D : public B {};
  struct D2 : virtual public D {};

  int B::*p;
  int D::*q;

  void f() {
    static_cast<int D2::*>(p);  // permitted
    static_cast<int D2::*>(q);  // forbidden
  }

Proposed resolution (October, 2005):

  1. Change 4.11  conv.mem paragraph 2 as indicated:

  2. ...If B is an inaccessible (clause 11  class.access), ambiguous (10.2  class.member.lookup) or virtual (10.1  class.mi) base class of D, or a base class of a virtual base class of D, a program that necessitates this conversion is ill-formed...
  3. Change 5.2.9  expr.static.cast paragraph 2 as indicated:

  4. ...and B is not neither a virtual base class of D nor a base class of a virtual base class of D...
  5. Change 5.2.9  expr.static.cast paragraph 9 as indicated:

  6. ...and B is not neither a virtual base class of D nor a base class of a virtual base class of D...



506. Conditionally-supported behavior for non-POD objects passed to ellipsis

Section: 5.2.2  expr.call     Status: ready     Submitter: Mike Miller     Date: 14 Apr 2005

The current wording of 5.2.2  expr.call paragraph 7 states:

When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (18.7  lib.support.runtime). The lvalue-to-rvalue (4.1  conv.lval), array-to-pointer (4.2  conv.array), and function-to-pointer (4.3  conv.func) standard conversions are performed on the argument expression. After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer to member, or class type, the program is ill-formed. If the argument has a non-POD class type (clause 9  class), the behavior is undefined.

Paper J16/04-0167=WG21 N1727 suggests that passing a non-POD object to ellipsis be ill-formed. In discussions at the Lillehammer meeting, however, the CWG felt that the newly-approved category of conditionally-supported behavior would be more appropriate.

Proposed resolution (October, 2005):

Change 5.2.2  expr.call paragraph 7 as indicated:

...After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer to member, or class type, the program is ill-formed. If the argument has a non-POD class type (clause 9), the behavior is undefined. Passing an argument of non-POD class type (clause 9) with no corresponding parameter is conditionally-supported, with implementation-defined semantics.



367. throw operator allowed in constant expression?

Section: 5.19  expr.const     Status: ready     Submitter: Martin v. Loewis     Date: 29 July 2002

The following translation unit appears to be well-formed.

int x[true?throw 4:5];

According to 5.19  expr.const, this appears to be an integral constant expression: it is a conditional expression, involves only literals, and no assignment, increment, decrement, function-call, or comma operators. However, if this is well-formed, the standard gives no meaning to this declaration, since the array bound (8.3.4  dcl.array paragraph 1) cannot be computed.

I believe the defect is that throw expressions should also be banned from constant expressions.

Notes from October 2002 meeting:

We should also check on new and delete.

Notes from the April, 2005 meeting:

Although it could be argued that all three of these operators potentially involve function calls — throw to std::terminate, new and delete to the corresponding allocation and deallocation functions — and thus would already be excluded from constant expressions, this reasoning was considered to be too subtle to allow closing the issue with no change. A modification that explicitly clarifies the status of these operators will be drafted.

Proposed resolution (October, 2005):

Change the last sentence of 5.19  expr.const as indicated:

In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call function call (including new-expressions and delete-expressions), or comma operators, or throw-expressions shall not be used.

Note: this sentence is also changed by the resolution of issue 530.




477. Can virtual appear in a friend declaration?

Section: 7.1.2  dcl.fct.spec     Status: ready     Submitter: Daveed Vandevoorde     Date: 23 Sep 2004

I couldn't find wording that makes it invalid to say friend virtual... The closest seems to be 7.1.2  dcl.fct.spec paragraph 5, which says:

The virtual specifier shall only be used in declarations of nonstatic class member functions that appear within a member-specification of a class definition; see 10.3  class.virtual.

I don't think that excludes a friend declaration (which is a valid member-specification by 9.2  class.mem).

John Spicer: I agree that virtual should not be allowed on friend declarations. I think the wording in 7.1.2  dcl.fct.spec is intended to be the declaration of a function within its class, although I think the wording should be improved to make it clearer.

Proposed resolution (October, 2005):

Change 7.1.2  dcl.fct.spec paragraphs 5-6 as indicated:

The virtual specifier shall only be used only in declarations the initial declaration of a non-static class member functions that appear within a member-specification of a class definition function; see 10.3  class.virtual.

The explicit specifier shall be used only in declarations the declaration of constructors a constructor within a its class definition; see 12.3.1  class.conv.ctor.




516. Use of signed in bit-field declarations

Section: 7.1.5.2  dcl.type.simple     Status: ready     Submitter: comp.std.c++     Date: 25 Apr 2005

7.1.5.2  dcl.type.simple paragraph 3 reads,

It is implementation-defined whether bit-fields and objects of char type are represented as signed or unsigned quantities. The signed specifier forces char objects and bit-fields to be signed; it is redundant with other integral types.

The last sentence in that quote is misleading w.r.t. bit-fields. The first sentence in that quote is correct but incomplete.

Proposed fix: change the two sentences to read:

It is implementation-defined whether objects of char type are represented as signed or unsigned quantities. The signed specifier forces char objects signed; it is redundant with other integral types except when declaring bit-fields (9.6  class.bit).

Proposed resolution (October, 2005):

Change 7.1.5.2  dcl.type.simple paragraph 3 as indicated:

When multiple simple-type-specifiers are allowed, they can be freely intermixed with other decl-specifiers in any order. [Note: It is implementation-defined whether bit-fields and objects of char type and certain bit-fields (9.6  class.bit) are represented as signed or unsigned quantities. The signed specifier forces bit-fields and char objects and bit-fields to be signed; it is redundant with other integral types in other contexts. end note]



454. When is a definition of a static data member required?

Section: 9.4.2  class.static.data     Status: ready     Submitter: Gennaro Prota     Date: 18 Jan 2004

As a result of the resolution of core issue 48, the current C++ standard is not in sync with existing practice and with user expectations as far as definitions of static data members having const integral or const enumeration type are concerned. Basically what current implementations do is to require a definition only if the address of the constant is taken. Example:

void f() {

  std::string s;
  ... 

  // current implementations don't require a definition
  if (s.find('a', 3) == std::string::npos) {
   ...
  }

To the letter of the standard, though, the above requires a definition of npos, since the expression std::string::npos is potentially evaluated. I think this problem would be easily solved with simple changes to 9.4.2  class.static.data paragraph 4, 9.4.2  class.static.data paragraph 5 and 3.2  basic.def.odr paragraph 3.

Suggested resolution:

Replace 9.4.2  class.static.data paragraph 4 with:

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 [note1] an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. No definition of the member is required, unless an lvalue expression that designates it is potentially evaluated and either used as operand to the built-in unary & operator [note 2] or directly bound to a reference.

If a definition exists, it shall be at namespace scope and shall not contain an initializer.

In 9.4.2  class.static.data paragraph 5 change

There shall be exactly one definition of a static data member that is used in a program; no diagnostic is required; see 3.2.

to

Except as allowed by 9.4.2 par. 4, there shall be exactly one definition of a static data member that is potentially evaluated (3.2) in a program; no diagnostic is required.

In 3.2  basic.def.odr paragraph 3 add, at the beginning:

Except for the omission allowed by 9.4.2, par. 4, ...

[note 1] Actually it shall be a "= followed by a constant-expression". This could probably be an editorial fix, rather than a separate DR.

[note 2] Note that this is the case when reinterpret_cast-ing to a reference, like in

struct X { static const int value = 0; };
const char & c = reinterpret_cast<const char&>(X::value);
See 5.2.10  expr.reinterpret.cast/10

More information, in response to a question about why issue 48 does not resolve the problem:

The problem is that the issue was settled in a way that solves much less than it was supposed to solve; that's why I decided to file, so to speak, a DR on a DR.

I understand this may seem a little 'audacious' on my part, but please keep reading. Quoting from the text of DR 48 (emphasis mine):

Originally, all static data members still had to be defined outside the class whether they were used or not.

But that restriction was supposed to be lifted [...]

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.

The corresponding resolution doesn't reflect this intent, with the definition being still required in most situations anyway: it's enough that the constant appears outside a place where constants are required (ignoring the obvious cases of sizeof and typeid) and you have to provide a definition. For instance:

  struct X {
   static const int c = 1;
  };

  void f(int n)
  {
   if (n == X::c)   // <-- potentially evaluated
    ...
  }

<start digression>

Most usages of non-enum BOOST_STATIC_COSTANTs, for instance, are (or were, last time I checked) non-conforming. If you recall, Paul Mensonides pointed out that the following template

// map_integral

template<class T, T V> struct map_integral : identity<T> {
  static const T value = V;
};

template<class T, T V> const T map_integral<T, V>::value;

whose main goal is to map the same couples (type, value) to the same storage, also solves the definition problem. In this usage it is an excellent hack (if your compiler is good enough), but IMHO still a hack on a language defect.

<end digression>

What I propose is to solve the issue according to the original intent, which is also what users expect and all compilers that I know of already do. Or, in practice, we would have a rule that exists only as words in a standard document.

PS: I've sent a copy of this to Mr. Adamczyk to clarify an important doubt that occurred to me while writing this reply:

if no definition is provided for an integral static const data member is that member an object? Paragraph 1.8/1 seems to say no, and in fact it's difficult to think it is an object without assuming/pretending that a region of storage exists for it (an object *is* a region of storage according to the standard).

I would think that when no definition is required we have to assume that it could be a non-object. In that case there's nothing in 3.2 which says what 'used' means for such an entity and the current wording would thus be defective. Also, since the name of the member is an lvalue and 3.10/2 says an lvalue refers to an object we would have another problem.

OTOH the standard could pretend it is always an object (though the compiler can optimize it away) and in this case it should probably make a special case for it in 3.2/2.

Notes from the March 2004 meeting:

We sort of like this proposal, but we don't feel it has very high priority. We're not going to spend time discussing it, but if we get drafting for wording we'll review it.

Proposed resolution (October, 2005):

  1. Change the first two sentences of 3.2  basic.def.odr paragraph 2 from:

    An expression is potentially evaluated unless it appears where an integral constant expression is required (see 5.19  expr.const), is the operand of the sizeof operator (5.3.3  expr.sizeof), or is the operand of the typeid operator and the expression does not designate an lvalue of polymorphic class type (5.2.8  expr.typeid). An object or non-overloaded function is used if its name appears in a potentially-evaluated expression.

    to

    An expression that is the operand of the sizeof operator (5.3.3  expr.sizeof) is unevaluated, as is an expression that is the operand of the typeid operator if it is not an lvalue of a polymorphic class type (5.2.8  expr.typeid); all other expressions are potentially evaluated. An object or non-overloaded function whose name appears as a potentially-evaluated expression is used, unless it is an object that satisfies the requirements for appearing in an integral constant expression (5.19  expr.const) and the lvalue-to-rvalue conversion (4.1  conv.lval) is immediately applied.
  2. Change the first sentence of 9.4.2  class.static.data paragraph 2 as indicated:

  3. 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 whose constant-expression shall be an integral constant expression (5.19  expr.const).



58. Signedness of bit fields of enum type

Section: 9.6  class.bit     Status: ready     Submitter: Steve Adamczyk     Date: 13 Oct 1998

Section 9.6  class.bit paragraph 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"?

(See also issue 172.)

Note (March, 2005): Clark Nelson observed that there is variation among implementations on this point.

Notes from April, 2005 meeting:

Although implementations enjoy a great deal of latitude in handling bit-fields, it was deemed more user-friendly to ensure that the example in paragraph 4 will work by requiring implementations to use an unsigned underlying type if the enumeration type has no negative values. (If the implementation is allowed to choose a signed representation for such bit-fields, the comparison against TRUE will be false.)

In addition, it was observed that there is an apparent circularity between 7.2  dcl.enum paragraph 7 and 9.6  class.bit paragraph 4 that should be resolved.

Proposed resolution (April, 2006):

  1. Replace 7.2  dcl.enum paragraph 7, deleting the embedded footnote 85, with the following:

    For an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values in the range bmin to bmax, defined as follows: Let K be 1 for a two's complement representation and 0 for a one's complement or sign-magnitude representation. bmax is the smallest value greater than or equal to max(|emin|-K,|emax|) and equal to 2M-1, where M is a non-negative integer. bmin is zero if emin is non-negative and -(bmax+K) otherwise. The size of the smallest bit-field large enough to hold all the values of the enumeration type is max(M,1) if bmin is zero and M+1 otherwise. It is possible to define an enumeration that has values not defined by any of its enumerators.
  2. Add the indicated text to the second sentence of 9.6  class.bit paragraph 4:

    If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type (7.2  dcl.enum), the original enumerator value and the value of the bit-field shall compare equal.



484. Can a base-specifier name a cv-qualified class type?

Section: 10  class.derived     Status: ready     Submitter: Richard Corden     Date: 21 Oct 2004

Issue 298, recently approved, affirms that cv-qualified class types can be used as nested-name-specifiers. Should the same be true for base-specifiers?

Rationale (April, 2005):

The resolution of issue 298 added new text to 9.1  class.name paragraph 5 making it clear that a typedef that names a cv-qualified class type is a class-name. Because the definition of base-specifier simply refers to class-name, it is already the case that cv-qualified class types are permitted as base-specifiers.

Additional notes (June, 2005):

It's not completely clear what it means to have a cv-qualified type as a base-specifier. The original proposed resolution for issue 298 said that “the cv-qualifiers are ignored,” but that wording is not in the resolution that was ultimately approved.

If the cv-qualifiers are not ignored, does that mean that the base-class subobject should be treated as always similarly cv-qualified, regardless of the cv-qualification of the derived-class lvalue used to access the base-class subobject? For instance:

    typedef struct B {
        void f();
        void f() const;
        int i;
    } const CB;

    struct D: CB { };

    void g(D* dp) {
        dp->f();    // which B::f?
        dp->i = 3;  // permitted?
    }

Proposed resolution (October, 2005):

  1. Change 9.1  class.name paragraph 5 as indicated:

  2. A typedef-name (7.1.3  dcl.typedef) that names a class type, or a cv-qualified version thereof, is also a class-name, but class-name. If a typedef-name that names a cv-qualified class type is used where a class-name is required, the cv-qualifiers are ignored. A typedef-name shall not be used as the identifier in a class-head.
  3. Delete 7.1.3  dcl.typedef paragraph 8:

  4. [Note: if the typedef-name is used where a class-name (or enum-name) is required, the program is ill-formed. For example,

        typedef struct {
            S();     // error: requires a return type because S is
                      // an ordinary member function, not a constructor
        } S;
    

    end note]




494. Problems with the resolution of issue 45

Section: 11  class.access     Status: ready     Submitter: Lloyd J. Lewins     Date: 17 Dec 2004

The proposed resolution for issue 45 inserts the following sentence after 11  class.access paragraph 1:

A member of a class can also access all names as the class of which it is a member.

I don't think that this is correctly constructed English. I see two possibilities:

  1. This is a typo, and the correct change is:

    A member of a class can also access all names of the class of which it is a member.

  2. The intent is something more like:

    A member of a nested class can also access all names accessible by any other member of the class of which it is a member.

[Note: this was editorially corrected at the time defect resolutions were being incorporated into the Working Paper to read, “...can also access all the names declared in the class of which it is a member,” which is essentially the same as the preceding option 1.]

I would prefer to use the language proposed for 11.8  class.access.nest:

A nested class is a member and as such has the same access rights as any other member.

A second problem is with the text in 11.4  class.friend paragraph 2:

[Note: this means that access to private and protected names is also granted to member functions of the friend class (as if the functions were each friends) and to the static data member definitions of the friend class. This also means that private and protected type names from the class granting friendship can be used in the base-clause of a nested class of the friend class. However, the declarations of members of classes nested within the friend class cannot access the names of private and protected members from the class granting friendship. Also, because the base-clause of the friend class is not part of its member declarations, the base-clause of the friend class cannot access the names of the private and protected members from the class granting friendship. For example,
    class A {
        class B { };
        friend class X;
    };
    class X : A::B {     // ill-formed: A::B cannot be accessed
                         // in the base-clause for X
        A::B mx;         // OK: A::B used to declare member of X
        class Y: A::B {  // OK: A::B used to declare member of X
            A::B my;     // ill-formed: A::B cannot be accessed
                         // to declare members of nested class of X
        };
    };
end note]

This seems to be an oversight. The proposed change to 11.8  class.access.nest paragraph 1 would appear to have eliminated the restrictions on nested class access. However, at least one compiler (gcc 3.4.3) doesn't appear to take my view, and continues with the restrictions on access by classes within a friend class, while implementing the rest of the resolution of issue 45.

Note (March, 2005):

Andreas Hommel: I think issue 45 requires an additional change in 9.7  class.nest paragraph 4:

Like a member function, a friend function (11.4  class.friend) defined within a nested class is in the lexical scope of that class; it obeys the same rules for name binding as a static member function of that class (9.4  class.static) and has no special access rights to members of an enclosing class.

I believe the “no special access rights” language should be removed.

Proposed resolution (October, 2005):

This issue is resolved by the resolution of issue 372.




500. Access in base-specifiers of friend and nested classes

Section: 11.4  class.friend     Status: ready     Submitter: Andreas Hommel     Date: 25 Jan 2005

I don't know the reason for this distinction, but it seems to be surprising that Base::A is legal and D is illegal in this example:

    class D;
    class Base 
    { 
        class A;
        class B;
        friend class D;
    }; 
    class Base::B 
    {
    };
    class Base::A : public Base::B  // OK because of issue 45
    { 
    };
    class D : public Base::B        // illegal because of 11.4p4
    { 
    };

Shouldn't this be consistent (either way)?

Notes from the April, 2005 meeting:

In discussing issue 372, the CWG decided that access in the base-specifiers of a class should be the same as for its members, and that resolution will apply to friend declarations, as well.

Proposed resolution (October, 2005):

This issue is resolved by the resolution of issue 372.




534. template-names and operator-function-ids

Section: 14  temp     Status: ready     Submitter: Jens Maurer     Date: 5 October 2005

Taken literally, 14  temp paragraph 2 does not permit operator functions to be templates:

In a function template declaration, the declarator-id shall be a template-name (i.e., not a template-id).

and, in 14.2  temp.names paragraph 1, a template-name is defined to be simply an identifier.

Issue 301 considered and rejected the idea of changing the definition of template-name to include operator-function-ids and conversion-function-ids. Either that decision should be reconsidered or the various references in the text to template-name should be examined to determine if they should also mention the non-identifier possibilities for function template names.

Proposed resolution (April, 2006):

This issue is resolved by the resolution of issue 301.




301. Syntax for template-name

Section: 14.2  temp.names     Status: ready     Submitter: Mark Mitchell     Date: 24 Jul 2001

The grammar for a template-name is:

That's not right; consider:

    template <class T> T operator+(const T&, const T&);
    template <> S operator+<S>(const S&, const S&);

This is ill-formed according to the standard, since operator+ is not a template-name.

Suggested resolution:

I think the right rule is

John Spicer adds that there's some question about whether conversion functions should be included, as they cannot have template argument lists.

Notes from 4/02 meeting:

If the change is made as a syntax change, we'll need a semantic restriction to avoid operator+<int> as a class. Clark Nelson will work on a compromise proposal -- not the minimal change to the syntax proposed, not the maximal change either.

Clark Nelson (April 2003):

The proposed solution (adding operator-function-id as an alternative for template-name) would have a large impact on the language described by the grammar. Specifically, for example, operator+<int> would become a syntactically valid class-name.

On the other hand, a change with (I believe) exactly the desired effect on the language accepted, would be to modify operator-function-id itself:

(Steve Adamczyk: this change was already made by issue 38 and is in TC1.)

Then there is the first sentence of 14.2  temp.names paragraph 3:

After name lookup (3.4  basic.lookup) finds that a name is a template-name, if this name is followed by a <, the < is always taken as the beginning of a template-argument-list and never as a name followed by the less-than operator.

This description seems to be adequate for names of class templates. As far as I can tell, the only ambiguity it resolves is from something that starts with new X <, in the scope of a class template X. But as far as I can tell is already inadequate for names of function templates, and is even worse for operator function templates.

Probably < should always be interpreted as introducing a template-argument-list if any member of the overload set is a function template. After all, function pointers are very rarely compared for ordering, and it's not clear what other rule might be workable.

I'm inclined to propose the simplest rule possible for operator-function-ids: if one is followed by <, then what follows is interpreted as a template-argument-list, unconditionally. Of course, if no template for that operator has been declared, then there's an error.

Also, note that if the operator in question is < or <<, it is possible to run into a problem similar to the famous >> nested template argument list closing delimiter problem. However, since in this case (at least) one of the < characters has a radically different interpretation than the other, and for other reasons as well, this is unlikely to be nearly as much of a practical problem as the >> problem.

Notes from April 2003 meeting:

We felt that the operator functions should not be special-cased. They should be treated like any other name.

September 2003:

Clark Nelson has provided the changes in N1490=03-0073.

Notes from October 2003 meeting:

We reviewed Clark Nelson's N1490. Clark will revise it and introduce a new syntax term for an identifier or the name of an operator function.

Notes from the April, 2005 meeting:

The CWG suggested a new approach to resolving this issue: the existing term template-id will be renamed to class-template-id, the term template-id will be defined to include operator functions with template arguments, and any current uses of template-id (such as in the definition of elaborated-type-specifier) where an operator function is not appropriate will be changed to refer to class-template-id.

Proposed resolution (April, 2006):

As specified in document J16/05-0156 = WG21 N1896, except that:

  1. In change 9 (3.4.5  basic.lookup.classref), omit the change from “entire postfix-expression” to “nested-name-specifier.”

  2. In change a (3.4.3.1  class.qual paragraph 1, third bullet), omit the change from “entire postfix-expression” to “qualified-id.”

  3. In change b (3.4.3.2  namespace.qual paragraph 1), omit the change from “entire postfix-expression” to “qualified-id.”

(Some of these omitted changes are addressed by issue 562.)

(This resolution also resolves issue 534.)




468. Allow ::template outside of templates

Section: 14.2  temp.names     Status: ready     Submitter: John Spicer     Date: 9 Apr 2004

For the same reasons that issue 382 proposes for relaxation of the requirements on typename, it would make sense to allow the ::template disambiguator outside of templates.

See also issues 11, 30, 96, and 109.

Proposed resolution (October, 2005):

Change 14.2  temp.names paragraph 5 as indicated:

If a name prefixed by the keyword template is not the name of a template, the program is ill-formed. [Note: the keyword template may not be applied to non-template members of class templates. —end note] 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 nested-name-specifier or the expression on the left of the -> or ., or the nested-name-specifier is not dependent on a template-parameter, or the use does not appear in the scope of a template. —end note]



372. Is access granted by base class specifiers available in following base class specifiers?

Section: 14.3  temp.arg     Status: ready     Submitter: Clark Nelson     Date: 13 August 2002

I'm not really sure what the standard says about this. Personally, I'd like for it to be ill-formed, but I can't find any words that I can interpret to say so.

  template<class T>
  class X
  {
  protected:
    typedef T Type;
  };
  template<class T>
  class Y
  {
  };
  template<class T,
           template<class> class T1,
           template<class> class T2>
  class Z:
    public T2<typename T1<T>::Type>,
    public T1<T>
  {
  };
  Z<int, X, Y> z;

John Spicer: I don't think the standard really addresses this case. There is wording about access checking of things used as template arguments, but that doesn't address accessing members of the template argument type (or template) from within the template.

This example is similar, but does not use template template arguments.

  class X {
  private:
    struct Type {};
  };
  template <class T> struct A {
    typename T::Type t;
  };
  A<X> ax;

This gets an error from most compilers, though the standard is probably mute on this as well. An error makes sense -- if there is no error, there is a hole in the access checking. (The special rule about no access checks on template parameters is not a hole, because the access is checked on the type passed in as an argument. But when you look up something in the scope of a template parameter type, you need to check the access to the member found.)

The logic in the template template parameter case should be similar: anytime you look up something in a template-dependent class, the member's access must be checked, because it could be different for different template instances.

Proposed Resolution (October 2002):

Change the last sentence of 14.3  temp.arg paragraph 3 from:

For a template-argument of class type, the template definition has no special access rights to the inaccessible members of the template argument type.
to:
For a template-argument that is a class type or a class template, the template definition has no special access rights to the members of the template-argument. [Example:
  template <template <class TT> class T> class A {
    typename T<int>::S s;
  };

  template <class U> class B {
    private:
    struct S { /* ... */ };
  };

  A<B> b;   // ill-formed, A has no access to B::S
-- end example]

Daniel Frey posts on comp.std.c++ in July 2003: I just read DR 372 and I think that the problem presented is not really discussed/solved properly. Consider this example:

  class A {
  protected:
     typedef int N;
  };

  template< typename T >
  class B
  {};

  template< typename U >
  class C : public U, public B< typename U::N >
  {};

  C< A > x;

The question is: If C is derived from A as above, is it allowed to access A::N before the classes opening '{'?

The main problem is that you need to access U's protected parts in C's base-clause. This pattern is common when using policies, Andrei's Loki library was bitten by it as he tried to make some parts of the policies 'protected' but some compilers rejected the code. They were right to reject it, I think it's 11.4  class.friend/2 that applies here and prevents the code above to be legal, although it addresses a different and reasonable example. To me, it seems wrong to reject the code as it is perfectly reasonable to write such stuff. The questions are:

Steve Adamczyk: In other words, the point of the issue is over what range access derived from base class specifiers is granted, and whether any part of that range is the base specifier list itself, either the parts afterwards or the whole base specifier list. (Clark Nelson confirms this is what he was asking with the original question.) Personally, I find it somewhat disturbing that access might arrive incrementally; I'd prefer that the access happen all at once, at the opening brace of the class.

Notes from October 2003 meeting:

We decided it makes sense to delay the access checking for the base class specifiers until the opening brace of the class is seen. In other words, the base specifiers will be checked using the full access available for the class, and the order of the base classes is not significant in that determination. The implementors present all said they already had code to handle accumulation of delayed access checks, because it is already needed in other contexts.

Proposed resolution (October, 2004):

  1. Change the last sentence of 14.3  temp.arg paragraph 3 as indicated:

    For a template-argument of that is a class type or a class template, the template definition has no special access rights to the inaccessible members of the template argument type template-argument. [Example:
        template <template <class TT> class T> class A {
           typename T<int>::S s;
        };
    
        template <class U> class B {
           private:
           struct S { /* ... */ };
        };
    
        A<B> b;   // ill-formed, A has no access to B::S
    

    end example]

  2. Insert the following as a new paragraph after the final paragraph of 11  class.access:

    The access of names in a class base-specifier-list are checked at the end of the list after all base classes are known. [Example:

        class A {
          protected:
             typedef int N;
        };
    
        template<typename T> class B {};
    
        template<typename U> class C : public B<typename U::N>, public U {};
    
        C<A> x;  // OK: A is a base class so A::N in B<A::N> is accessible
    

    end example]

Notes from the April, 2005 meeting:

The 10/2004 resolution is not sufficient to implement the CWG's intent to allow these examples: clause 11  class.access paragraph 1 grants protected access only to “members and friends” of derived classes, not to their base-specifiers. The resolution needs to be extended to say either that access in base-specifiers is determined as if they were members of the class being defined or that access is granted to the class as an entity, including its base-specifiers. See also issue 500, which touches on the same issue and should be resolved in the same way.

Proposed resolution (October, 2005):

  1. Change the second bullet of 11  class.access paragraph 1 as indicated:

  2. Change 11  class.access paragraph 2 as indicated:

    A member of a class can also access all the names declared in the class of which it is a member to which the class has access.
  3. Change 11  class.access paragraph 6 as indicated:

    All access controls in clause 11  class.access affect the ability to access a class member name from a particular scope. The access control for names used in the definition of a class member that appears outside of the member's class definition is done as if the entire member definition appeared in the scope of the member's class. For purposes of access control, the base-specifiers of a class and the definitions of class members that appear outside of the class definition are considered to be within the scope of that class. In particular...
  4. Change the example and commentary in 11  class.access paragraphs 6-7 as indicated:

    [Example:

        class A {
          typedef int I; // private member
          I f();
          friend I g(I);
          static I x;
        protected:
          struct B { };
        };
    
        A::I A::f () { return 0; }
        A::I g(A::I p = A::x);
        A::I g(A::I p) { return 0; }
        A::I A::x = 0;
    
        struct D: A::B, A { };
    
    Here, all the uses of A::I are well-formed because A::f and A::x are members of class A and g is a friend of class A. This implies, for example, that access checking on the first use of A::I must be deferred until it is determined that this use of A::I is as the return type of a member of class A. Similarly, the use of A::B as a base-specifier is well-formed because D is derived from A, so access checking of base-specifiers must be deferred until the entire base-specifier-list has been seen.end example]
  5. In 11.4  class.friend paragraph 2, replace the following text:

    Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in declarations of members of the befriended class. [Note: this means that access to private and protected names is also granted to member functions of the friend class (as if the functions were each friends) and to the static data member definitions of the friend class. This also means that private and protected type names from the class granting friendship can be used in the base-clause of a nested class of the friend class. However, the declarations of members of classes nested within the friend class cannot access the names of private and protected members from the class granting friendship. Also, because the base-clause of the friend class is not part of its member declarations, the base-clause of the friend class cannot access the names of the private and protected members from the class granting friendship. For example,

        class A {
          class B { };
          friend class X;
        };
        class X: A::B {     // ill-formed: A::B cannot be accessed
                            // in the base-clause for X
          A::B mx;          // OK: A::B used to declare member of X
          class Y: A::B {   // OK: A::B used to declare member of X
            A::B my;        // ill-formed: A::B cannot be accessed
                            // to declare members of nested class of X
          };
        };
    

    end note]

    with:

    Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in the base-specifiers and member declarations of the befriended class. [Example:

        class A {
          class B { };
          friend class X;
        };
    
        struct X: A::B {   // OK: A::B accessible to friend
          A::B mx;         // OK: A::B accessible to member of friend
          class Y {
            A::B my;       // OK: A::B accessible to nested member of friend
          };
        };
    

    end example]

  6. Change the last sentence of 14.3  temp.arg paragraph 3 as indicated:

    For a template-argument of that is a class type or a class template, the template definition has no special access rights to the inaccessible members of the template argument type. template-argument. [Example:

    
        template <template <class TT> class T> class A {
          typename T<int>::S s;
        };
    
        template <class U> class B {
        private:
          struct S { /* ... */ };
        };
    
        A<B> b;    // ill-formed, A has no access to B::S
    
    

    end example]

  7. Change 9.7  class.nest paragraph 4 as indicated:

    Like a member function, a friend function (11.4  class.friend) defined within a nested class is in the lexical scope of that class; it obeys the same rules for name binding as a static member function of that class (9.4  class.static), but it and has no special access rights to members of an enclosing class.

(Note: this resolution also resolves issues 494 and 500.)




517. Partial specialization following explicit instantiation

Section: 14.5.4  temp.class.spec     Status: ready     Submitter: John Spicer     Date: 03 May 2005

According to 14.5.4  temp.class.spec paragraph 1,

If a template is partially specialized then that partial specialization shall be declared before the first use of that partial specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.

This leaves the impression that an explicit instantiation of the primary template may precede the declaration of an applicable partial specialization. Is the following example well-formed?

    template<typename T> class X{
        public:
        void foo(){};
    };

    template class X<void *>;

    template<typename T> class X<T*>{
        public:
        void baz();
    };

    void bar() {
        X<void *> x;
        x.foo();
    }

Proposed resolution (October, 2005):

Replace the last sentence of 14.5.4  temp.class.spec paragraph 1:

If a template is partially specialized then that partial specialization shall be declared before the first use of that partial specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.

with:

A partial specialization shall be declared before the first use of a class template specialization that would make use of the partial specialization as the result of an implicit or explicit instantiation in every translation unit in which such a use occurs; no diagnostic is required.



515. Non-dependent references to base class members

Section: 14.6.2  temp.dep     Status: ready     Submitter: Mike Miller     Date: 18 Apr 2005

Implementations vary in their treatment of the following code:

    struct A {
      int foo_;
    };
    template <typename T> struct B: public A { };
    template <typename T> struct C: B<T> {
      int foo() {
        return A::foo_;  // #1
      }
    };
    int f(C<int>* p) {
      return p->foo();
    }

According to one analysis, because the expression A::foo_ on line #1 is non-dependent, it must be analyzed in the definition context. It that context, it violates the restrictions of 9.2  class.mem paragraph 10 on how the name of a nonstatic data member of a class can be used and thus should be treated as an error.

On the other hand, the description of the transformation of an id-expression into a class member access expression (9.3.1  class.mfct.nonstatic paragraph 3) does not have any special treatment of templates; when C<int>::foo() is instantiated, the reference to A::foo_ turns out to be to a base class member and is thus transformed into (*this).A::foo_ and is thus not an error.

Proposed resolution (October, 2005):

Change 9.3.1  class.mfct.nonstatic paragraph 3 as indicated:

When an id-expression (5.1  expr.prim) that is not part of a class member access syntax (5.2.5  expr.ref) and not used to form a pointer to member (5.3.1  expr.unary.op) is used in the body of a non-static member function of class X or used in the mem-initializer for a constructor of class X, if name lookup (3.4.1  basic.lookup.unqual) resolves the name in the id-expression to a non-static non-type member of class X or of a base class of X some class C, the id-expression is transformed into a class member access expression (5.2.5  expr.ref) using (*this) (9.3.2  class.this) as the postfix-expression to the left of the . operator. [Note: If C is not X or a base class of X, the class member access expression is ill-formed. —end note] The member name then refers to the member of the object for which the function is called. Similarly during name lookup...



524. Can function-notation calls to operator functions be dependent?

Section: 14.6.2  temp.dep     Status: ready     Submitter: Daveed Vandevoorde     Date: 19 July 2005

The description of dependent function calls in 14.6.2  temp.dep paragraph 1 applies only to identifiers in postfix-notation function calls and to operator notation calls for operator functions:

In an expression of the form:

where the postfix-expression is an identifier, the identifier denotes a dependent name if and only if any of the expressions in the expression-list is a type-dependent expression (14.6.2.2  temp.dep.expr). If an operand of an operator is a type-dependent expression, the operator also denotes a dependent name.

It would appear from the related passage in 14.6.4.2  temp.dep.candidate paragraph 1 that the description of postfix-notation function calls should apply to all unqualified-ids that are not template-ids, including operator-function-ids, not just to identifiers:

For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found...

Proposed resolution (October, 2005):

  1. Change 14.6.2  temp.dep paragraph 1 as indicated:

  2. ...In an expression of the form:

    where the postfix-expression is an identifier unqualified-id but not a template-id, the identifier unqualified-id denotes a dependent name if and only if any of the expressions in the expression-list is a type-dependent expression (14.6.2.2  temp.dep.expr)...

  3. Change 14.6.4.2  temp.dep.candidate paragraph 1 as indicated:

  4. For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, or if the function is called using operator notation, the candidate functions are found using the usual lookup rules (3.4.1  basic.lookup.unqual, 3.4.2  basic.lookup.argdep) except that...

(See also issue 561.)




522. Array-to-pointer decay in template argument deduction

Section: 14.8.2.1  temp.deduct.call     Status: ready     Submitter: Daveed Vandevoorde     Date: 3 June 2005

Consider the following example:

    char* cmdline3_[1] = {};

    template<class charT>
    void func(const charT* const argv[]) {}

    int main()
    {
        func(cmdline3_);
    }

In terms of the process described in 14.8.2.1  temp.deduct.call, P is const charT* const * and A is char*[1]. According to the first bullet in paragraph 2, the type used in deduction is not A but “the pointer type produced by the array-to-pointer standard conversion.”

According to paragraph 4,

In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:

In this example, the deduced A is not identical to the transformed A, because the deduced A has additional cv-qualification, so the three exceptions must be examined to see if they apply. The only one that might apply is the second bullet of paragraph 4:

However, A is not a pointer type but an array type; this provision does not apply and deduction fails.

It has been argued that the phrase “after the type A is transformed as described above” should be understood to apply to the A in the three bullets of paragraph 4. If that is the intent, the wording should be changed to make that explicit.

Proposed resolution (October, 2005):

Add the indicated words to 14.8.2  temp.deduct paragraph 4:

In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:




526. Confusing aspects in the specification of non-deduced contexts

Section: 14.8.2.5  temp.deduct.type     Status: ready     Submitter: Mike Miller     Date: 25 July 2005

14.8.2.5  temp.deduct.type paragraph 5 reads:

The non-deduced contexts are:

There are two problems with this list:

  1. The last bullet is redundant with the second bullet. This appears to have been the result of applying the resolutions of issues 70 and 352 independently instead of in coordination.

  2. The second bullet appears to be contradicted by the statement in paragraph 8 saying that an argument can be deduced if P and A have the forms type[i] and template-name<i>.

    The intent of the wording in bullet 2 appears to have been that deduction cannot be done if the template parameter is a sub-expression of the template argument or array bound expression and that it can be done if it is the complete expression, but the current wording does not say that very clearly. (Similar wording also appears in 14.6.2.1  temp.dep.type paragraph 3 and 14.8.2.5  temp.deduct.type paragraph 14.)

Proposed resolution (October, 2005):

  1. Change 14.8.2.5  temp.deduct.type paragraph 5 as indicated:

  2. The non-deduced contexts are:

  3. Change 14.8.2.5  temp.deduct.type paragraph 14 as indicated:

  4. If, in the declaration of a function template with a non-type template parameter, the non-type template parameter is used in an expression a subexpression in the function parameter list, the expression is a non-deduced context as specified above...
  5. Change 14.6.2.1  temp.dep.type paragraph 3 as indicated:

  6. A template argument that is equivalent to a template parameter (i.e., has the same constant value or the same type as the template parameter) can be used in place of that template parameter in a reference to the current instantiation. In the case of a non-type template argument, the argument must have been given the value of the template parameter and not an expression involving that contains the template parameter as a subexpression...



415. Template deduction does not cause instantiation

Section: 14.8.3  temp.over     Status: ready     Submitter: John Spicer     Date: 4 May 2003

Mike Miller: In fact, now that I've looked more closely, that appears not to be the case. (At least, it's not the error I get when I compile his example.) Here's a minimal extract (without the inflammatory using-directive :-) that illustrates what I think is going on:

  template <typename _Iterator>
  struct iterator_traits {
    typedef typename _Iterator::difference_type difference_type;
  };

  template <typename _InputIterator>
  inline typename iterator_traits<_InputIterator>::difference_type
  distance(_InputIterator, _InputIterator);

  double distance(const int&, const int&);

  void f() {
    int i = 0;
    int j = 0;
    double d = distance(i, j);
  }

What happens is that iterator_traits<int> is instantiated as part of type deduction for the function template distance, and the instantiation fails. (Note that it can't be instantiation of distance<int>, as I had originally posited, because in this case only a declaration, not a definition, of that template is in scope.)

John Spicer: Yes, I believe that is what is going on.

Mike Miller: I seem to recall that there was some discussion of questions related to this during the core meetings in Oxford. I think Steve Adamczyk said something to the effect that it's infeasible to suppress all instantiation errors during template type deduction and simply call any such errors a deduction failure. (I could be misremembering, and I could be misapplying that comment to this situation.)

John Spicer: Regardless of other conditions in which this may apply, I don't think it would be reasonable for compilers to have to do "speculative instantiations" during template argument deduction. One class instantiation could kick off a series of other instantiations, etc.

Mike Miller: I don't see anything in the Standard that tells me whether it's legitimate or not to report an error in this case. I hope John or another template expert can enlighten me on that.

John Spicer: My opinion is that, because this case is not among those enumerated that cause deduction failure (rather than being ill-formed) that reporting an error is the right thing to do.

Mike Miller: I am still interested, though, in the question of why 14.8.3  temp.over says that viable function template specializations are instantiated, even if they are not selected by overload resolution.

John Spicer: I believe the wording in 14.8.3  temp.over is incorrect. I researched this and found that a change was made during the clause 14 restructuring that was incorporated in March of 1996. The prior wording was "the deduced template arguments are used to generate a single template function". This was changed to "deduced template arguments are used to instantiate a single function template specialization". I believe this resulted from what was basically a global replace of "generate" with "instantiate" and of "template function" with "function template specialization". In this case, the substitution changed the meaning. This paragraph needs reworking.

Proposed resolution (April, 2006):

Change 14.8.3  temp.over paragraph 1 as indicated:

...For each function template, if the argument deduction and checking succeeds, the template-arguments (deduced and/or explicit) are used to instantiate synthesize the declaration of a single function template specialization which is added to the candidate functions set to be used in overload resolution. If, for a given function template, argument deduction fails, no such function is added to the set of candidate functions for that template. The complete set of candidate functions includes all the function templates instantiated in this way synthesized declarations and all of the non-template overloaded functions of the same name. The function template specializations synthesized declarations are treated like any other functions in the remainder of overload resolution, except as explicitly noted in 13.3.3  over.match.best.



370. Can #include <...> form be used other than for standard C++ headers?

Section: 16.2  cpp.include     Status: ready     Submitter: Beman Dawes     Date: 01 August 2002

The motivation for this issue is a desire to write portable programs which will work with any conforming implementation.

The C++ Standard (16.2  cpp.include) provides two forms of #include directives, with the <...> form being described (16.2  cpp.include paragraph 2) as "for a header", and the "..." form (16.2  cpp.include paragraph 3) as for "the source file" identified between the delimiters. When the standard uses the term "header", it often appears to be limiting the term to apply to the Standard Library headers only. Users of the standard almost always use the term "header" more broadly, to cover all #included source files, but particularly those containing interface declarations.

Headers, including source files, can be categorized according to their origin and usage:

  1. C++ Standard Library headers (which aren't necessarily files).
  2. Other standard libraries such as the POSIX headers.
  3. Operating system API's such as windows.h.
  4. Third party libraries, such as Boost, ACE, or commercial offerings.
  5. Organization-wide "standard" header files, such as a company's config.hpp.
  6. A project's "public" header files, often shared by all developers working on the same project.
  7. A project or user's "private", "local", or "detail" headers, in the same directory or sub-directory as the compilation unit.

Existing practice varies widely, but it is fairly easy to find users advocating:

Do any of the practices A, B, or C result in programs which can be rejected by a conforming implementation?

The first defect is that readers of the standard have not been able to reach consensus on the answers to the above question.

A second possible defect is that if A, B, or C can be rejected by a conforming implementation, then the standard should be changed because would mean there is a wide variance between the standard and existing practice.

Matt Austern: I really only see two positions:

  1. Implementations have some unspecified mechanism (copying files to a magic directory, adding a magic flag,...) such that the line #include <foo> results in textual inclusion of the file foo.
  2. Implementations are not required to have any mechanism for getting #include <foo> to perform textual inclusion of an arbitrary file foo. That form is reserved for standard library headers only.

I agree that the standard should clarify which of those two is the case (I imagine it'll hinge on finding one crucual sentence that either says "implementation defined" or "unspecified"), but from the standpoint of portability I don't see much difference between the two. I claim that, with either of those two interpretations, using #include <foo> is already nonportable.

(Of course, I claim that almost anything having to do with headers, including the #include "foo" form, is also nonportable. In practice there's wide variation in how compilers handle paths, especially relative paths.)

Beman Dawes: The whole issue can be resolved by replacing "header" with "header or source file" in 16.2  cpp.include paragraph 2. That will bring the standard into alignment with existing practice by both users and implementations. The "header and/or source file" wording is used at least three other places in the standard where otherwise there might be some confusion.

John Skaller: In light of Andrew Koenig's comments, this doesn't appear to be the case, since the mapping of include names to file names is implementation defined, and therefore source file inclusion cannot be made portable within the ISO C/C++ standards (since that provision obviously cannot be removed).

A possible idea is to create a binding standard, outside the C/C++ ISO Standards, which specifies not only the path lookup mechanism but also the translation from include names to file names. Clearly that is OS dependent, encoding dependent, etc, but there is no reason not to have a binding standard for Unix, Windows, etc, and specify these bindings in such a way that copying directories from one OS to the other can result in programs working on both OS's.

Andy Koenig: An easier solution might be to specify a (presumably unbounded, or bounded only by implementation capacit