This document contains the C++ core language issues that have been
categorized as Defect Reports by the Committee (PL22.16 +
WG21) and other accepted issues, that is, issues with status
"DR,"
"accepted,"
"DRWP,"
"WP,"
"CD1,"
"CD2,"
"TC1," and
"FDIS,"
along with their proposed resolutions. Issues with DR,
accepted, DRWP, and WP status are NOT part of the International
Standard for C++. They are provided for informational
purposes only, as an indication of the intent of the Committee.
They should not be considered definitive until or unless they
appear in an approved Technical Corrigendum or revised
International Standard for C++.

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:

Active Issues List, which contains
explanatory material for the entire document group and a list of
the issues that have not yet been acted upon by the Committee.

Closed Issues List, which contains
the issues which the Committee has decided are not defects
in the International Standard, including a brief rationale
explaining the reason for the decision.

Table of Contents, which contains a
summary listing of all issues in numerical order.

Index by Section, which contains a
summary listing of all issues arranged in the order of the
sections of the Standard with which they deal most directly.

Index by Status, which contains a
summary listing of all issues grouped by status.

For more information, including a description of the meaning of
the issue status codes and instructions on reporting new issues,
please see the Active Issues List.

Section references in this document reflect the section numbering
of document
WG21 N3376.

Issues with "DR" Status

912.
Character literals and universal-character-names

A character literal that does not begin with u, U,
or L is an ordinary character literal, also referred to as a
narrow-character literal. An ordinary character literal that contains
a single c-char has type char, with value equal to the
numerical value of the encoding of the c-char in the execution
character set.

However, the definition of c-char includes as one
possibility a universal-character-name. The value of a
universal-character-name cannot, in general, be represented
as a char, so this specification is impossible to
satisfy.

See the discussion in issue 1422 for a
possible interpretation of the existing text.

Proposed resolution (February, 2012):

Change 2.14.3 [lex.ccon] paragraph 1 as follows:

...A character literal that does not begin with u,
U, or L is an ordinary character literal, also
referred to as a narrow-character literal. An ordinary character
literal that contains a single c-charrepresentable in
the execution character set has type char,
with value equal to the numerical value of the encoding of the
c-char in the execution character set. An ordinary character
literal that contains more than one c-char is a
multicharacter literal. A multicharacter literal, or an
ordinary character literal containing a single c-char not
representable in the execution character set, is
conditionally-supported, has type int, and
has an implementation-defined value.

1024.
Limits on multicharacter literals

There is no limit placed on the number of c-chars in a
multicharacter literal or a wide-character literal containing
multiple c-chars, either in 2.14.3 [lex.ccon]
paragraphs 1-2 or in Annex B [implimits]. Presumably
this means that an implementation must accept arbitrarily long
literals.

An alternative approach might be to state that these literals
are conditionally supported with implementation-defined semantics,
allowing an implementation to impose a documented limit that
makes sense for the particular architecture.

1438.
Non-dereference use of invalid pointers

The current Standard says that any use of an invalid pointer value
produces undefined behavior (3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 4).
This includes not only dereferencing the pointer but even just
fetching its value. The reason for this draconian restriction is that
some architectures in the past used dedicated address registers for
pointer loads and stores and they could fault if, for example, a
segment number in a pointer was not currently mapped.

It is not clear whether such restrictions are necessary with
architectures currently in use or reasonably foreseen. This should
be investigated to see if the restriction can be loosened to apply
only to dereferencing the pointer.

If the argument given to a deallocation function in the standard
library is a pointer that is not the null pointer value (4.10 [conv.ptr]), the deallocation function shall deallocate the storage
referenced by the pointer, rendering invalid all pointers referring to
any part of the deallocated storage. The effect of using
an invalid pointer value (including passing it to a deallocation
function) is undefinedIndirection through an invalid
pointer value and passing an invalid pointer value to a deallocation
function have undefined behavior. Any other use of an invalid pointer
value has implementation-defined behavior. [Footnote:On someSome implementations, itmight define that copying an invalid pointer value causes a
system-generated runtime fault. —end footnote]

1302.
noexcept applied to expression of type void

The list of acceptable uses of an expression of type void
in 3.9.1 [basic.fundamental] paragraph 9 does not, but should, include
an operand of the noexcept operator.

Proposed resolution (August, 2011):

Change 3.9.1 [basic.fundamental] paragraph 9 as follows:

An expression of type void shall be used only as an
expression statement (6.2 [stmt.expr]), as an operand of a
comma expression (5.18 [expr.comma]), as a second or third
operand of ?: (5.16 [expr.cond]), as the operand of
typeid, noexcept, or decltype,
as the expression in a return statement (6.6.3 [stmt.return])
for a function with the return type void, or as the operand
of an explicit conversion to type cvvoid.

1059.
Cv-qualified array types (with rvalues)

In spite of the resolution of issue 112,
the exact relationship between cv-qualifiers and array types is not
clear. There does not appear to be a definitive normative statement
answering the question of whether an array with a const-qualified
element type is itself const-qualified; the statement in
3.9.3 [basic.type.qualifier] paragraph 5,

Cv-qualifiers applied to an array type attach to the underlying
element type, so the notation “cvT,”
where T is an array type, refers to an array whose
elements are so-qualified. Such array types can be said to be
more (or less) cv-qualified than other types based on the
cv-qualification of the underlying element types.

hints at an answer but is hardly decisive. For example, is
the following example well-formed?

(The more general question is, when the Standard refers to
non-class types, should it be considered to include array types?
Or perhaps only arrays of non-class types?)

Proposed resolution (December, 2011):

Change 3.9.3 [basic.type.qualifier] paragraph 5 as follows:

...Cv-qualifiers applied to an array type attach to the underlying
element type, so the notation “cvT,”
where T is an array type, refers to an array whose elements are
so-qualified. Such array types can be said to be more (or less)
cv-qualified than other types based on the cv-qualification of the
underlying element types.An array type whose elements are
cv-qualified is also considered to have the same cv-qualification as
its elements. [Example:

The presence of a const specifier in a decl-specifier-seq
declares an object of const-qualified object type; such object is
called a const object.

Because the type of an object created by a new-expression is
given by a type-id or new-type-id rather than with a
decl-specifier-seq, this definition gives the false impression
that objects of dynamic storage duration cannot be const objects. The
wording should be adjusted to make it clear that they can.

Proposed resolution (February, 2012):

Change 3.9.3 [basic.type.qualifier] paragraph 1 as follows:

The term object type (1.8 [intro.object]) includes the
cv-qualifiers specified in the decl-specifier-seq
(7.1 [dcl.spec]), declarator (Clause
8 [dcl.decl]), type-id (8.1 [dcl.name]), or
new-type-id (5.3.4 [expr.new]) when the object
is created. The presence of a const specifier in a
decl-specifier-seq declares an object of
const-qualified object type; such object is called a const
object. The presence of a volatile specifier in a
decl-specifier-seq declares an object of volatile-qualified object
type; such object is called a volatile object. The presence of both
cv-qualifiers in a decl-specifier-seq declares an object of
const-volatile-qualified object type; such object is called a const
volatile object.

A const object is an object of type const T
or a non-mutable subobject of such an object.

A volatile object is an object of type
volatile T, a subobject of such an object, or a mutable
subobject of a const volatile object.

A const volatile object is an object of type
const volatile T, a non-mutable subobject of such an
object, a const subobject of a volatile object, or a non-mutable
volatile subobject of a const object.

The cv-qualified or cv-unqualified versions of a type are distinct
types; however, they shall have the same representation and alignment
requirements (3.9 [basic.types]).51

Change 3.9.3 [basic.type.qualifier] paragraph 3 as follows:

Each non-static, non-mutable, non-reference data member of a
const-qualified class object is const-qualified, each non-static,
non-reference data member of a volatile-qualified class object is
volatile-qualified and similarly for members of a const-volatile
class. See 8.3.5 [dcl.fct] and 9.3.2 [class.this] regarding function types...

1423.
Convertibility of nullptr to bool

The resolution of issue 654 (found
in paper N2656) enabled conversion of rvalues of type
std::nullptr_t to bool. It appears that the use
cases for this conversion are primarily or exclusively the
“contextually converted to bool” cases, with
some possibility for inadvertent misuse in other contexts. Paper
N2656 mentioned the idea of limiting the conversions to the
direct initialization contexts; that possibility should be
reexamined.

Proposed resolution (February, 2012):

Change 4.12 [conv.bool] paragraph 1 as follows:

...any other value is converted to true. AFor direct-initialization (8.5 [dcl.init]), a
prvalue of type std::nullptr_t can be converted to a prvalue
of type bool; the resulting value is false.

Class prvalues can have cv-qualified types; non-class
prvalues always have cv-unqualified types. Unless otherwise
indicated (5.2.2 [expr.call]), prvalues shall always
have complete types or the void type; in addition to
these types, glvalues can also have incomplete types.
[Note: class and array prvalues can have cv-qualified
types; other prvalues always have cv-unqualified types. See
Clause 5 [expr]. —end note]

Add a new paragraph following 5 [expr]
paragraph 5:

If an expression initially has the type “reference to
T”...

If a prvalue initially has the type “cvT,” where T is a cv-unqualified
non-class, non-array type, the type of the expression is adjusted
to T prior to any further analysis.

Change 5.2.2 [expr.call] paragraph 3 as follows:

If the postfix-expression designates a destructor
(12.4 [class.dtor]), the type of the function call
expression is void; otherwise, the type of the function
call expression is the return type of the statically chosen
function (i.e., ignoring the virtual keyword), even if
the type of the function actually called is different. This
return type shall be an object type, a reference type
or the typecvvoid.

Change 5.2.3 [expr.type.conv] paragraph 2 as follows:

...[Note: if T is a non-class type that is cv-qualified, the
cv-qualifiers are ignoreddiscarded
when determining the type of the resulting prvalue
(3.10 [basic.lval]Clause
5 [expr]). —end note]

Change 5.4 [expr.cast] paragraph 1 as follows:

...[Note: if T is a non-class type that is
cv-qualifiedcv-qualified, the
cv-qualifiers are ignoreddiscarded
when determining the type of the resulting prvalue; see
3.10 [basic.lval]Clause
5 [expr]. —end note]

1383.
Clarifying discarded-value expressions

There are some points in the description discarded-value expressions
that need clarification:

Does this require the lvalue-to-rvalue conversion in
the listed cases or only prohibit it in all other cases
(“only if” vs “if and only if”)?

Does this apply only to built-in operations or to overloaded
operators?

Does this apply to non-POD types?

Suggested resolution:

In some contexts, an expression only appears for its side
effects. Such an expression is called a discarded-value
expression. The expression is evaluated and its value is
discarded. The array-to-pointer (4.2 [conv.array]) and
function-to-pointer (4.3 [conv.func]) standard
conversions are not applied. The lvalue-to-rvalue conversion
(4.1 [conv.lval]) is applied if and only if
the expression is an lvalue of volatile-qualified type and it has
one of the following forms:

id-expression (5.1.1 [expr.prim.general]),

subscriptingsubscript operation
(5.2.1 [expr.sub]),

class member access (5.2.5 [expr.ref]),

indirection operation (5.3.1 [expr.unary.op]),

pointer-to-member operation (5.5 [expr.mptr.oper]),

conditional expressionoperation
(5.16 [expr.cond]) where both the second and the third
operands are one of the abovethese forms,
or

comma expressionoperation
(5.18 [expr.comma]) where the right operand is one of the
abovethese forms.

[Note: Expressions invoking user-defined operators
are not the operations above. Discarded-value expressions apply
to class types, which will be ill-formed if there is no volatile
copy constructor with which to initialize the
temporary. —end note]

Proposed resolution (February, 2012):

Change 5 [expr] paragraph 10 as follows:

...The lvalue-to-rvalue conversion (4.1 [conv.lval]) is
applied if and only if the expression is an lvalue of
volatile-qualified type and it hasis one of the
following forms:

(expression), where
expression is one of these expressions,

id-expression (5.1.1 [expr.prim.general]),

...

conditional expression (5.16 [expr.cond]) where both
the second and the third operands are one of the abovethese expressions, or

comma expression (5.18 [expr.comma]) where the right
operand is one of the abovethese
expressions.

[Note: Using an overloaded operator causes a function
call; the above covers only operators with built-in meaning. If the
lvalue is of class type, it must have a volatile copy constructor to
initialize the temporary that is the result of the lvalue-to-rvalue
conversion. —end note]

Additional note (February, 2012):

A problem was discovered that was not addressed by the proposed
resolution that was reviewed at the February, 2012 meeting, so the
issue has been moved back to "review" status with revised wording.

1440.
Acceptable decltype-specifiers used as nested-name-specifiers

The current wording of the Standard does not describe what happens
when a decltype-specifier is used as a
nested-name-specifier and the type denoted by the
decltype-specifier is neither a class type nor an
enumeration type. Such nested-name-specifiers should be
prohibited, presumably somewhere around paragraphs 8-10 of
5.1.1 [expr.prim.general]. (The corresponding prohibition for
named types is handled as part of lookup in 3.4.3 [basic.lookup.qual] paragraph 1.)

Proposed resolution (February, 2012):

Add the following immediately after the grammar in
5.1.1 [expr.prim.general] paragraph 8 and move the text following
that point into a new paragraph:

The type denoted by a decltype-specifier in a
nested-name-specifier shall be a class or enumeration
type.

A nested-name-specifier that denotes a class...

1269.
dynamic_cast of an xvalue operand

5.2.7 [expr.dynamic.cast] paragraph 2 allows an expression of any value
category when the target type is an rvalue reference. However, paragraph
6 requires that the operand be an lvalue if the runtime check is to be
applied. This requirement should presumably be relaxed to require only a
glvalue when the target type is an rvalue reference.

Proposed resolution (August, 2011):

Change 5.2.7 [expr.dynamic.cast] paragraph 6 as follows:

Otherwise, v shall be a pointer to or an lvaluea glvalue of a polymorphic type (10.3 [class.virtual]).

Additional note, January, 2012:

An objection has been raised
to the proposed resolution on the
basis that it unnecessarily weakens the distinction between rvalues
and lvalues, making it easier to create dangling references. Its
status has therefore been changed back to "review" to allow further
discussion.

1416.
Function cv-qualifiers and typeid

The top-level cv-qualifiers of the glvalue expression or the
type-id that is the operand of typeid are always
ignored

could be misinterpreted as referring to cv-qualifiers in a
function type, even though it is clear that a function type is never
cv-qualified. A note emphasizing the fact that that is not the
case would be helpful.

Proposed resolution (February, 2012):

Change 5.2.8 [expr.typeid] paragraph 5 as follows:

The top-level cv-qualifiers of the glvalue expression or the
type-id that is the operand of typeid are always
ignored.If the type of the expression or type-id is
a cv-qualified type, the result of the typeid expression
refers to a std::type_info object representing the
cv-unqualified type. [Example:...

1447.
static_cast of bit-field lvalue to rvalue reference

A glvalue of type “cv1T1” can be cast to
type “rvalue reference to cv2T2,” if
“cv2T2” is reference-compatible with
“cv1T1” (8.5.3 [dcl.init.ref]).
The result refers to the object or the specified base class subobject
thereof.

This specification fails to allow for a bit-field lvalue operand,
since the reference cannot refer to a bit-field. Presumably a
temporary should be formed and the reference be bound to it.

Proposed resolution (February, 2012):

Change 5.2.9 [expr.static.cast] paragraphs 3-4 as follows:

A glvalue of type “cv1T1” can be cast
to type “rvalue reference to cv2T2” if
“cv2T2” is reference-compatible with
“cv1T1” (8.5.3 [dcl.init.ref]).
TheIf the glvalue is not a bit-field, the
result refers to the object or the specified base class subobject
thereof; otherwise, the lvalue-to-rvalue conversion (4.1 [conv.lval]) is applied to the bit-field and the resulting prvalue is
used as the expression of the static_cast for the
remainder of this section. If T2 is an inaccessible
(Clause 11 [class.access]) or ambiguous (10.2 [class.member.lookup]) base class of T1, a program that necessitates
such a cast is ill-formed.

Otherwise, anAn expression e can be
explicitly converted...

1268.
reinterpret_cast of an xvalue operand

5.2.10 [expr.reinterpret.cast] paragraph 11, dealing with casting to
reference types, only allows an lvalue operand. Presumably it should
allow a glvalue operand when the target is an rvalue reference type.

Proposed resolution (August, 2011):

Change 5.2.10 [expr.reinterpret.cast] paragraph 11:

An lvalueA glvalue expression of type
T1 can be cast to the type “reference to
T2” if an expression of type “pointer to
T1” can be explicitly converted to the type
“pointer to T2” using a
reinterpret_cast. The result refers to the same object
as the source glvalue, but with the specified
type. [Note: That is, for lvalues, a reference
cast reinterpret_cast<T&>(x) has the same effect as
the conversion *reinterpret_cast<T*>(&x) with the
built-in & and * operators (and similarly for
reinterpret_cast<T&&>(x)). —end
note]The result refers to the same object as the source
lvalue, but with a different type. The result is an lvalue for an
lvalue reference type or an rvalue reference to function type and an
xvalue for an rvalue reference to object type. No temporary is
created,...

Additional note, January, 2012:

An objection has been raised
to the proposed resolution on the
basis that it unnecessarily weakens the distinction between rvalues
and lvalues, making it easier to create dangling references. Its
status has therefore been changed back to "review" to allow further
discussion.

342.
Terminology: "indirection" versus "dereference"

Incidentally, another thing that ought to be cleaned up is the inconsistent
use of "indirection" and "dereference". We should pick one.

Proposed resolution (December, 2006):

Change 5.3.1 [expr.unary.op] paragraph 1 as follows:

The unary *
operator performs indirectiondereferences a pointer
value: the expression to which it is applied shall be a pointer...

Change 8.3.4 [dcl.array] paragraph 8 as follows:

The results are added and indirection appliedvalues are
added and the result is dereferenced to yield an array (of five
integers), which in turn is converted to a pointer to the first of the
integers.

Change 8.3.5 [dcl.fct] paragraph 9 as follows:

The binding of *fpi(int) is *(fpi(int)), so the
declaration suggests, and the same construction in an expression
requires, the calling of a function fpi, and then using
indirection throughdereferencing the (pointer) result
to yield an integer. In the declarator (*pif)(const char*, const
char*), the extra parentheses are necessary to indicate that
indirection throughdereferencing a pointer to a
function yields a function, which is then called.

Change the index for * and “dereferencing”
no longer to refer to “indirection.”

[Drafting note: 26.6.9 [template.indirect.array]
requires no change. Many more places in the current wording use
“dereferencing” than “indirection.”]

Notes from the August, 2011 meeting:

CWG prefers use of the term “indirection” instead of
“dereferencing.” This would be consistent with the usage
in the C Standard and would avoid entanglement with the C++ concept
of a reference type.

Proposed resolution (February, 2012):

Change 3.7.4.1 [basic.stc.dynamic.allocation] paragraph 2 as follows:

...The effect of dereferencingindirecting
through a pointer returned as a request for zero size is
undefined.

Change 3.7.4.3 [basic.stc.dynamic.safety] paragraph 2 as follows:

the value returned by a call to the C ++ standard library
implementation of ::operator new(std:: size_t);
[Footnote: This section does not impose restrictions on
dereferencingindirection through pointers to
memory not allocated by ::operator new. This maintains the
ability of many C++ implementations to use binary libraries and
components written in other languages. In particular, this applies to
C binaries, because dereferencingindirection
through pointers to memory allocated by
std::malloc is not restricted. —end
footnote]

the result of taking the address of an object (or one of its
subobjects) designated by an lvalue resulting from
dereferencingindirection through a
safely-derived pointer value;

...

Change 3.8 [basic.life] paragraph 5 as follows:

...SuchIndirection through such a pointer
may be dereferencedis permitted but the
resulting lvalue may only be used in limited ways...

Change 4.11 [conv.mem] paragraph 2 as follows:

...Since the result has type “pointer to member of D of
type cvT”, it can be dereferencedindirection through it with a D object is
valid. The result is the same as if indirecting
through the pointer to member of Bwere
dereferenced with the B subobject of D. The
null member pointer value...

Change 5.2.9 [expr.static.cast] paragraph 12 as follows:

...[Note: although class B need not contain the
original member, the dynamic type of the object onwith which indirection through the pointer to
member is dereferencedperformed must contain
the original member; see 5.5 [expr.mptr.oper]. —end
note]

Change 5.3.1 [expr.unary.op] paragraph 1 as follows:

...[Note:indirection through a pointer to an
incomplete type (other than cvvoid) can be
dereferencedis valid. The lvalue thus obtained...

Change 5.10 [expr.eq] paragraph 2 as follows:

...Otherwise they compare equal if and only if they would refer to the
same member of the same most derived object (1.8 [intro.object])
or the same subobject if they were dereferencedindirection with a hypothetical object of the associated
class type were performed. [Example:...

Change 7.5 [dcl.link] paragraph 8:

[Note: Because the language linkage is part of a function type,
when indirecting through a pointer to C function (for
example) is dereferenced, the function to which itthe resulting lvalue refers is considered a C
function. —end note]

Change 8.3.2 [dcl.ref] paragraph 5 as follows:

...[Note: in particular, a null reference cannot exist in a
well-defined program, because the only way to create such a reference
would be to bind it to the “object” obtained by
dereferencingindirection through a null
pointer, which causes undefined behavior. As described...

Change 17.6.3.5 [allocator.requirements] table 27:

Variable

Definition

...

c

a dereferenceable pointer of type C*through which indirection is valid

...

Change 20.6.3.2 [pointer.traits.functions] as follows:

Returns: The first member function returns a
dereferenceable pointer to r obtained by calling
Ptr::pointer_to(r)through which indirection is
valid; an instantiation of this function is ill-formed...

Change 20.6.4 [util.dynamic.safety] paragraph 10 as follows:

Effects: The n bytes starting at p no longer
contain traceable pointer locations, independent of their type. Hence
pointersindirection through a pointer located
there may not be dereferencedis undefined if
the object they pointit points to was created
by global operator new and not previously declared
reachable...

Change 20.6.12 [specialized.algorithms] paragraph 1 as follows:

...is required to have the property that no exceptions are thrown from
increment, assignment, comparison, or dereference ofindirection through valid iterators...

Change 22.4.5.1.2 [locale.time.get.virtuals] paragraph 11 as follows:

Requires:t shall be dereferenceablepoint to an object.

Change 23.4.4.2 [map.cons] paragraph 3 as follows:

Requires: If the iterator's dereferenceindirection operator returns an lvalue or a const rvalue
pair<key_type, mapped_type>, then both
key_type and mapped_type shall be
CopyConstructible.

Change 23.4.5.2 [multimap.cons] paragraph 3 as follows:

Requires: If the iterator's dereferenceindirection operator returns an lvalue or a const rvalue
pair<key_type, mapped_type>, then both key_type and
mapped_type shall be CopyConstructible.

Change 23.4.6.2 [set.cons] paragraph 4 as follows:

Requires: If the iterator's dereferenceindirection operator returns an lvalue or a non-const
rvalue, then Key shall be CopyConstructible.

Change 23.4.7.2 [multiset.cons] paragraph 3 as follows:

Requires: If the iterator's dereferenceindirection operator returns an lvalue or a const rvalue,
then Key shall be CopyConstructible.

Change 24.5.3 [move.iterators] paragraph 1 as follows:

Class template move_iterator is an iterator adaptor with the
same behavior as the underlying iterator except that its
dereferenceindirection operator implicitly
converts the value returned by the underlying iterator's
dereferenceindirection operator to an rvalue
reference...

Change the title of 28.12.1.3 [re.regiter.deref] as follows:

regex_iteratordereferenceindirection

Change the title of 28.12.2.3 [re.tokiter.deref] as follows:

regex_token_iteratordereferenceindirection

1458.
Address of incomplete type vs operator&()

The address of an object of incomplete type can be taken, but if the
complete type of that object is a class type that declares
operator&() as a member function, then the behavior is
undefined (and no diagnostic is required).

This should actually be “ill-formed, no diagnostic
required” instead of undefined behavior, since the problem
could be detected by whole-program analysis. Also, it's not clear
what this means for constant expressions.

Proposed resolution (February, 2012):

Change 5.3.1 [expr.unary.op] paragraph 5 as follows:

The address of an object of incomplete type can be taken, but if
the complete type of that object is a class type that declares
operator&() as a member function, then the behavior is
undefined (and no diagnostic is required).If
& is applied to an lvalue of incomplete class type and
the complete type declares operator&(), it is unspecified
whether the operator has the built-in meaning or the operator function
is called. The operand of & shall not be a
bit-field.

1354.
Destructor exceptions for temporaries in noexcept expressions

The result of the noexcept operator does not consider possible
exceptions thrown by the destructors for temporaries created in the
operand expression.

Proposed resolution (February, 2012):

Change 1.9 [intro.execution] paragraph 10 as follows:

A full-expression is an expression that is not a subexpression
of another expression. [Note: in some contexts such as
unevaluated operands, a syntactic subexpression is considered a
full-expression (Clause 5 [expr]). —end
note] If a language construct...

Change 5 [expr] paragraph 7 as follows:

...An unevaluated operand is not evaluated. An unevaluated
operand is considered a full-expression. [Note:...

[Drafting note: This uniformly handles sizeof(A()),
noexcept(A()), typeid(A()), and
decltype(A()) with regard to the semantic requirements on
~A (accessible and not deleted), which might be checked via
SFINAE. A programmer can use decltype(new A) to avoid
considering the destructor. If this is undesired, an alternative
change just addresses the noexecept issue:]

[Editing note: all the occurrences of “potentially
evaluated” in 5.3.7 [expr.unary.noexcept] paragraph 3 should
be hyphenated.]

1450.
INT_MIN % -1

...if the quotient a/b is representable in the type of the result,
(a/b)*b + a%b is equal to a.

in an attempt to ensure that INT_MAX % -1 produces
undefined behavior (because the result is not specified by the
Standard). However, the new C draft makes the undefined behavior
explicit:

If the quotient a/b is representable, the expression
(a/b) * b + a%b shall equal a; otherwise, the
behavior of both a/b and a%b is undefined.

Should C++ adopt similar wording?

Proposed resolution (February, 2012):

Change 5.6 [expr.mul] paragraph 4 as follows:

...If the second operand of / or % is zero the
behavior is undefined. For integral operands the / operator
yields the algebraic quotient with any fractional part
discarded;81 if the quotient a/b is representable
in the type of the result, (a/b)*b + a%b is equal to
a; otherwise, the behavior of both a/b and
a%b is undefined.

1457.
Undefined behavior in left-shift

The current wording of 5.8 [expr.shift] paragraph 2 makes it
undefined behavior to create the most-negative integer of a given type
by left-shifting a (signed) 1 into the sign bit, even though
this is not uncommonly done and works correctly on the majority of
(twos-complement) architectures:

...if E1 has a signed type and non-negative value, and E1
⨯ 2E2 is representable in the result type, then
that is the resulting value; otherwise, the behavior is undefined.

As a result, this technique cannot be used in a constant expression,
which will break a significant amount of code.

Proposed resolution (February, 2012):

Change 5.8 [expr.shift] paragraph 2 as follows:

...if E1 has a signed type and non-negative value, and E1
⨯ 2E2 is representable in the corresponding
unsigned type of the result type, then that value,
converted to the result type, is the resulting value; otherwise,
the behavior is undefined.

1312.
Simulated reinterpret_cast in constant expressions

Although a reinterpret_cast is prohibited in a constant
expression, casting to and from void* can achieve the same
effect.

Proposed resolution (August, 2011):

Change 5.19 [expr.const] paragraph 2 as follows:

an lvalue-to-rvalue conversion (4.1 [conv.lval])
unless it is applied to...

an lvalue-to-rvalue conversion (4.1 [conv.lval])
that is applied to a glvalue of type cv1T that refers
to an object of type cv2U, where T and
U are neither the same type nor similar types (4.4 [conv.qual]);

an lvalue-to-rvalue conversion (4.1 [conv.lval]) that
is applied to a glvalue that refers to a non-active member...

Note, January, 2012:

Additional discussion has occurred, so this issue has been returned to
"review" status to allow further consideration.

Proposed resolution (February, 2012):

Change 5.19 [expr.const] paragraph 2 as follows:

...

an id-expression that refers to a variable or data
member of reference type unless...

A conditional-expression is a core constant
expression unless it involves one of the following...

...

an invocation of a constexpr function with arguments
that, when substituted by function invocation substitution
(7.1.5 [dcl.constexpr]), do not produce a core
constant expression; [Example:...

an invocation of a constexpr constructor with
arguments that, when substituted by function invocation substitution
(7.1.5 [dcl.constexpr]), do not produce all core
constant expressions for the constructor calls and full-expressions in
the mem-initializers; [Example:...

...

an lvalue-to-rvalue conversion (4.1 [conv.lval])
unless it is applied to

...

a glvalue of literal type that refers to a non-volatile
temporary object whose lifetime has not ended, initialized with a
core constant expression;

...

an id-expression that refers to a variable or data
member of reference type unless the reference has a preceding
initialization, initialized with a constant expression;and either

it is initialized with a constant expression or

it is a non-static data member of a temporary object whose
lifetime has not ended and is initialized with a core constant
expression;

...

Change 5.19 [expr.const] paragraph 3 as follows,
dividing it into two paragraphs:

A literal constant expression is a prvalue core
constant expression of literal type, but not pointer type. An
integral constant expression is a literal constantan expression of integral or unscoped enumeration
type, implicitly converted to a prvalue, where the converted
expression is a core constant expression. [Note: Such
expressions may be used as array bounds (8.3.4 [dcl.array],
5.3.4 [expr.new]), as bit-field lengths (9.6 [class.bit]), as enumerator initializers if the underlying type is not
fixed (7.2 [dcl.enum]), as null pointer constants
(4.10 [conv.ptr]), and as alignments (7.6.2 [dcl.align]). —end note] A converted constant
expression of type T is a literal constantan expression, implicitly converted to a prvalue
of type T, where the implicit conversion (if any)
is permitted in a literalconverted expression is a
core constant expression and the implicit conversion sequence
contains only user-defined conversions, lvalue-to-rvalue conversions
(4.1 [conv.lval]), integral promotions (4.5 [conv.prom]), and integral conversions (4.7 [conv.integral])
other than narrowing conversions (8.5.4 [dcl.init.list]). [Note: such expressions may be used as case
expressions (6.4.2 [stmt.switch]), as enumerator initializers
if the underlying type is fixed (7.2 [dcl.enum]), and as
integral or enumeration non-type template arguments (14.3 [temp.arg]). —end note]

A literal constant expression is a prvalue core
constant expression of literal type, but not pointer type (after
conversions as required by the context). For a literal constant
expression of array or class type, each subobject of its value shall
have been initialized by a constant expression. A reference
constant expression is an lvalue core constant expression that
designates an object with static storage duration or a function. An
address constant expression is a prvalue core constant
expression (after conversions as required by the context) of type
std::nullptr_t or of pointer type that evaluates to the
address of an object with static storage duration, to the address of a
function, or to a null pointer value, or a prvalue core constant
expression of type std::nullptr_t. Collectively,
literal constant expressions, reference constant expressions, and
address constant expressions are called
constant expressions.

Change the second example 7.1.5 [dcl.constexpr] paragraph
5 as follows:

1455.
Lvalue converted constant expressions

A "converted constant expression" must be a literal constant
expression, which is a prvalue, and thus can't be an lvalue. This is
unintended; the lvalue-to-rvalue conversion should be applied as
necessary.

631.
Jumping into a “then” clause

6.4.1 [stmt.if] is silent about whether the else
clause of an if statement is executed if the condition is not
evaluated. (This could occur via a goto or a longjmp.)
C99 covers the goto case with the following provision:

If the first substatement is reached via a label, the second
substatement is not executed.

It should probably also be stated that the condition is not
evaluated when the “then” clause is entered directly.

Proposed resolution (February, 2012):

Change 6.4.1 [stmt.if] paragraph 1 as follows:

If the condition (6.4 [stmt.select]) yields true the
first substatement is executed. If the else part of the
selection statement is present and the condition yields
false, the second substatement is executed. If the first
substatement is reached via a label, the condition is not evaluated
and the second substatement is not executed. In the second
form...

1359.
constexpr union constructors

A constexpr constructor is required to initialize all
non-static data members (7.1.5 [dcl.constexpr] paragraph 4),
which conflicts with the requirement that a constructor for a union
is permitted to initialize only a single non-static data member
(12.6.2 [class.base.init] paragraph 8).

Proposed resolution (February, 2012):

Change 7.1.5 [dcl.constexpr] paragraph 4 as follows:

In a definition of a constexpr constructor, each of the
parameter types shall be a literal type. In addition, either its
function-body shall be = delete or = default
or it shall satisfy the following constraints:

1439.
Lookup and friend template declarations

If a friend declaration in a non-local class first
declares a class or function95 the friend class or
function is a member of the innermost enclosing namespace. The
name of the friend is not found by unqualified lookup
(3.4.1 [basic.lookup.unqual]) or by qualified lookup (3.4.3 [basic.lookup.qual]) until a matching declaration is provided in that
namespace scope (either before or after the class definition
granting friendship).

This wording does not, but probably should, apply to friend
declarations of function templates and class templates as well.

Every name first declared in a namespace is a member of that
namespace. If a friend declaration in a non-local class first
declares a class,or function, class
template, or function template95 the friend
class or function is a member of the innermost enclosing
namespace. The name of the friend is not found by unqualified lookup
(3.4.1 [basic.lookup.unqual]) or by qualified lookup (3.4.3 [basic.lookup.qual]) until a matching declaration is provided in that
namespace scope (either before or after the class definition granting
friendship). If a friend function or function template is
called, its name may be found by the name lookup that considers
functions from namespaces and classes associated with the types of the
function arguments (3.4.2 [basic.lookup.argdep]). If the name in a
friend declaration...

1382.
Dead code for constructor names

Issue 147 changed the name lookup rules
so that a lookup that would have found the injected-class-name of a
class will refer to the constructor. However, there still appear to
be vestiges of the earlier specification that were not removed by
the resolution. For example, the grammar in 8 [dcl.decl]
paragraph 4 contains,

declarator-id:

...opt id-expressionnested-name-specifieropt class-name

It would seem that there is no longer any need for the second
line, since a lookup for a declarator-id will not produce
a class-name. Similarly, 5.1.1 [expr.prim.general]
paragraph 8 still contains the sentence,

Where class-name::class-name is used,
and the two class-names refer to the same class, this
notation names the constructor (12.1 [class.ctor]).

Proposed resolution (February, 2012):

Change 8 [dcl.decl] paragraph 4 as follows:

...declarator-id:

...opt id-expressionnested-name-specifieropt class-name

A class-name has special meaning in a declaration of the
class of that name and when qualified by that name using the scope
resolution operator :: (,
12.1 [class.ctor], 12.4 [class.dtor]).

Change 5.1.1 [expr.prim.general] paragraph 8 as follows:

...[Note: a class member can be referred to using a
qualified-id at any point in its potential scope (3.3.7 [basic.scope.class]). —end note] Where class-name::class-name is used, and the two class-names
refer to the same class, this notation names the constructor
(12.1 [class.ctor]). Where class-name::~class-name is used...

1380.
Type definitions in template-parameterparameter-declarations

Although 8.3.5 [dcl.fct] paragraph 9 forbids defining a
type in a parameter declaration, and a template parameter declaration is
syntactically a parameter-declaration, the context in
8.3.5 [dcl.fct] function declarators. It's therefore not
completely clear that that prohibition applies to template parameter
declarations as well. This should be clarified.

Proposed resolution (February, 2012):

Change 14.1 [temp.param] paragraph 2 as follows:

...A storage class shall not be specified in a
template-parameter declaration. Types shall not be defined
in a template-parameter declaration. [Note:...

1394.
Incomplete types as parameters of deleted functions

The type of a parameter or the return type for a function
definition shall not be an incomplete class type (possibly
cv-qualified) unless the function definition is nested within the
member-specification for that class (including definitions in
nested classes defined within the class).

There is no reason for this requirement for a function with a
deleted definition, and it would be useful to relax this prohibition
in such cases.

Proposed resolution (February, 2012):

Change 8.3.5 [dcl.fct] paragraph 9 as follows:

Types shall not be defined in return or parameter types. The type of
a parameter or the return type for a function definition shall not be
an incomplete class type (possibly cv-qualified) unless the function
is deleted (8.4.3 [dcl.fct.def.delete]) or the definition
is nested within the member-specification for that class
(including definitions in nested classes defined within the class).

1401.
Similar types and reference compatibility

The definition of reference-compatible types in
8.5.3 [dcl.init.ref] paragraph 4 allows the types to differ
in top-level cv-qualification, but it does not encompass the deeper
added cv-qualification permitted for “similar types”
(4.4 [conv.qual]). This seems surprising and could lead
to errors resulting from the fact that the reference will be bound
to a temporary and not to the original object in the initializer.

Proposed resolution (February, 2012):

Change 8.5.3 [dcl.init.ref] paragraph 4 as follows:

Given types “cv1T1” and “cv2T2,” “cv1T1” is
reference-related to “cv2T2” if
T1 is the same type as T2, or T1 is a base
class of T2. “cv1T1” is
reference-compatible with “cv2T2” if
T1 is reference-related to T2 and cv1 is the
same cv-qualification as, or greater cv-qualification than,
cv2. For purposes of overload resolution, cases for which
cv1 is greater cv-qualification than cv2 are identified
as reference-compatible with added qualification (see
13.3.3.2 [over.ics.rank]). In all cases...

Delete 13.3.3.1.4 [over.ics.ref] paragraph 5:

The binding of a reference to an expression that is
reference-compatible with added qualification influences the
rank of a standard conversion; see 13.3.3.2 [over.ics.rank] and
8.5.3 [dcl.init.ref].

[Drafting note: CWG decided not to make a substantive change for
this issue, but the investigation discovered that the term defined by
these two citations is not actually used and could be
removed.]

1270.
Brace elision in array temporary initialization

Issue 1232 extended the language to allow
creation of array temporaries using initializer lists. However, such
initializer lists must be “completely braced;” the elision
of braces described in 8.5.1 [dcl.init.aggr] paragraph 11 applies
only

In a declaration of the form

T x = { a };

This restriction prevents plausible uses like

array<int, 3> f() {
return { 1, 2, 3 };
}

Proposed resolution (February, 2012):

Change 8.5.1 [dcl.init.aggr] paragraph 11 as follows:

In a declaration of the form

T x = { a };

bracesBraces can be elided in an
initializer-list as follows. [Footnote: Braces
cannot be elided in other uses of list-initialization. —end
footnote]

1290.
Lifetime of the underlying array of an initializer_list member

A question has arisen over expected behavior when an
initializer_list is a non-static data member of a class.
Initialization of an initializer_list is defined in terms of
construction from an implicitly allocated array whose lifetime "is the
same as that of the initializer_list object". That would
mean that the array needs to live as long as the
initializer_list does, which would on the face of it appear
to require the array to be stored in something like a
std::unique_ptr<T[]> within the same class (if the
member is initialized in this manner).

It would be surprising if that was the intent, but it would make
initializer_list usable in this context.

It would also be reasonable if this behaved similarly to binding
temporaries to reference members (i.e., "temporary bound to a
reference member in a constructor's ctor-initializer
(12.6.2 [class.base.init]) persists until the constructor exits."),
though this approach would probably prevent use of an
initializer_list member in that context.

Proposed resolution (February, 2012):

Change 8.5.4 [dcl.init.list] paragraphs 5-6 as
follows:

An object of type std::initializer_list<E> is
constructed from an initializer list as if the implementation
allocated ana temporary array of N
elements of type E, where...

The lifetime of the array is the same as that of the
initializer_list object.The array has the same
lifetime as any other temporary object (12.2 [class.temporary]),
except that initializing an initializer_list object from the
array extends the lifetime of the array exactly like binding a
reference to a temporary. [Example:

For v1 and v2, the initializer_list object
is a parameter in a function call, so theand
array created for { 1, 2, 3 }havehas
full-expression lifetime. For i3, the
initializer_list object is a variable, so theand array have automaticpersists for
the lifetime of the variable. For i4, the
initializer_list object is initialized in a constructor's
ctor-initializer, so the array persists only until the
constructor exits, and so any use of the elements of i4 after
the constructor exits produces undefined behavior. —end
example] [Note: The implementation is free to allocate the
array in read-only memory if an explicit array with the same
initializer could be so allocated. —end note]

Change 12.2 [class.temporary] paragraph 5 as follows:

The second context is when a reference is bound to a temporary.
[Footnote: The same rules apply to initialization of an
initializer_list object (8.5.4 [dcl.init.list]) with its
underlying temporary array. —end footnote] The
temporary to which...

1418.
Type of initializer_list backing array

According to 8.5.4 [dcl.init.list] paragraph 5, the
elements of the backing array for an object of type
std::initializer_list<E> are of type
E. This is contradicted by the wording of
18.9 [support.initlist] paragraph 2.

Proposed resolution (February, 2012):

Change 8.5.4 [dcl.init.list] paragraph 5 as follows:

An object of type std::initializer_list<E> is
constructed from an initializer list as if the implementation
allocated an array of N elements of type const
E, where N is the number of elements in the initializer
list. Each element of that array is copy-initialized with the
corresponding element of the initializer list, and the
std::initializer_list<E> object is constructed to refer
to that array. If a narrowing conversion is required to initialize
any of the elements, the program is ill-formed. [Example:

struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };

The initialization will be implemented in a way roughly equivalent
to this:

1449.
Narrowing conversion of negative value to unsigned type

According to 8.5.4 [dcl.init.list] paragraph 7, an implicit
conversion

from an integer type or unscoped enumeration type to an integer type
that cannot represent all the values of the original type, except
where the source is a constant expression and the actual value after
conversion will fit into the target type and will produce the original
value when converted back to the original type.

As is made plain in the examples in that paragraph, a conversion of
a negative value to an unsigned type is intended to be a narrowing
conversion; however, the phrase “actual value after
conversion” makes this intent unclear, especially since the
round-trip conversion between signed and unsigned types might well
yield the original value.

Proposed resolution (February, 2012):

Change 8.5.4 [dcl.init.list] paragraph 7 as follows:

A narrowing conversion is an implicit conversion

...

from an integer type or unscoped enumeration type to an integer
type that cannot represent all the values of the original type, except
where the source is a constant expression and the actual value
after conversionwhose value after integral
promotions will fit into the target type and will produce the
original value when converted back to the original type.

[Note:...

1363.
Triviality vs multiple default constructors

Section: 9 [class]
Status: DR
Submitter: Sean Hunt
Date: 2011-08-16

[Moved to DR at the October, 2012 meeting.]

The requirements for a trivial class include having “a trivial
default constructor” (9 [class] paragraph 6).
However, with an explicitly-defaulted default constructor and other
constructors with default arguments, it is possible to have multiple
default constructors. Such a class cannot be default-initialized and
thus should probably be considered non-trivial.

Proposed resolution (February, 2012):

Change 9 [class] paragraph 6 as follows:

...A trivial class is a class that has a trivial
default constructor (12.1 [class.ctor]), has no
non-trivial default constructors, and is trivially
copyable...

675.
Signedness of bit-field with typedef or template parameter type

Is the signedness of x in the following example
implementation-defined?

template <typename T> struct A {
T x : 7;
};
template struct A<long>;

A similar example could be created with a typedef.

Lawrence Crowl: According to 9.6 [class.bit]
paragraph 3,

It is implementation-defined whether a plain (neither explicitly
signed nor unsigned) char, short, int
or long bit-field is signed or unsigned.

This clause is conspicuously silent on typedefs and template
parameters.

Clark Nelson: At least in C, the intention is that the
presence or absence of this redundant keyword is supposed to be
remembered through typedef declarations. I don't remember discussing
it in C++, but I would certainly hope that we don't want to do
something different. And presumably, we would want template type
parameters to work the same way.

So going back to the original example, in an instantiation of
A<long>, the signedness of the bit-field is
implementation-defined, but in an instantiation of A<signed
long>, the bit-field is definitely signed.

Peter Dimov: How can this work?
Aren't A<long> and A<signed long> the
same type?

739.
Signedness of plain bit-fields

It is implementation-defined whether a plain (neither explicitly
signed nor unsigned) char, short, int or
long bit-field is signed or unsigned.

The implications of this permission for an implementation that
chooses to treat plain bit-fields as unsigned are not clear. Does
this mean that the type of such a bit-field is adjusted to the
unsigned variant or simply that sign-extension is not performed when
the value is fetched? C99 is explicit in specifying the former (6.7.2
paragraph 5: “for bit-fields, it is implementation-defined
whether the specifier int designates the same type as
signed int or the same type as unsigned
int”), while C90 takes the latter approach (6.5.2.1:
“Whether the high-order bit position of a (possibly qualified)
'plain' int bit-field is treated as a sign bit is
implementation-defined”).

As an example of the implications of this question, consider the
following declaration:

struct S {
int i: 2;
signed int si: 2;
unsigned int ui: 2;
} s;

Is it implementation-defined which expression,
cond?s.i:s.si or cond?s.i:s.ui, is an lvalue (the
lvalueness of the result depends on the second and third operands
having the same type, per 5.16 [expr.cond] paragraph 4)?

Proposed resolution (August, 2011):

Change 9.6 [class.bit] paragraph 3 as follows:

A bit-field shall not be a static member. A bit-field shall have
integral or enumeration type (3.9.1 [basic.fundamental]). It is
implementation-defined whether a plain (neither explicitly signed nor
unsigned) char, short, int, long,
or long long bit-field is signed or unsigned.For a bit-field with a non-dependent type (14.6.2.1 [temp.dep.type])
that is specified to be plain (neither explicitly signed nor unsigned)
short, int, long, or long long or a
typename-name that is so defined (possibly through multiple
levels of typedefs), it is implementation-defined whether the
type of the bit-field is the corresponding signed or unsigned
type. [Example:

It is implementation-defined whether B::x has type
signed long or unsigned long. B::y has
type signed int. It is implementation-defined whether
B::z has type signed int or unsigned int.
A<int>::x and A<signed int>::x designate
the same entity of type signed int. A<unsigned
int>:;x has type unsigned int. —end
example]

Additional questions have been raised about the proposed resolution,
so the status was returned to "review" to allow further discussion.

Proposed resolution (February, 2012):

Change 9.6 [class.bit] paragraph 3 as follows:

A bit-field shall not be a static member. A bit-field shall have
integral or enumeration type (3.9.1 [basic.fundamental]). It is
implementation-defined whether a plain (neither explicitly signed nor
unsigned) char, short, int, long,
or long long bit-field is signed or unsigned. A
bool value can successfully be stored...

Add the following as a new section in C.1.8 [diff.class]:

9.6 [class.bit]

Change: Bit-fields of type plain int are signed.

Rationale: Leaving the choice of signedness to implementations
could lead to inconsistent definitions of template specializations. For
consistency, the implementation freedom was eliminated for non-dependent
types, too.

Effect on original feature: The choice is implementation-defined
in C, but not so in C++.

1392.
Explicit conversion functions for references and non-references

In 13.3.1.5 [over.match.conv], dealing with non-reference
initialization, direct initialization considers as candidate functions
only those that

yield type T or a type that can be converted to type
T with a qualification conversion

By contrast, 13.3.1.6 [over.match.ref], dealing with reference
binding, requires only that the type returned be reference-compatible
with the target, permitting both qualification conversions and
derived-to-base conversions. This discrepancy is presumably
unintentional.

Proposed resolution (February, 2012):

Change 13.3.1.6 [over.match.ref] paragraph 1 as follows:

...the candidate functions are selected as follows:

The conversion functions of S and its base classes
are considered, except that for copy-initialization, only the
non-explicit conversion functions are considered. Those
non-explicit conversion functions that are not hidden
within S and yield type “lvalue reference to
cv2T2” (when 8.5.3 [dcl.init.ref]
requires an lvalue result) or “cv2T2” or
“rvalue reference to cv2T2” (when
8.5.3 [dcl.init.ref] requires an rvalue result), where
“cv1T” is reference-compatible
(8.5.3 [dcl.init.ref]) with “cv2T2”, are candidate functions. For
direct-initialization, those explicit conversion functions that are not
hidden within S and yield type “lvalue reference to
cv2T2,” or “cv2T2 or
“rvalue reference to cv2T2,”
respectively, where T2 is the same type as T or can
be converted to type T with a qualification conversion
(4.4 [conv.qual]), are also candidate
functions.

1409.
What is the second standard conversion sequence of a list-initialization sequence?

Both paragraphs 3 and 4 (for non-aggregate and aggregate
types, respectively) of 13.3.3.1.5 [over.ics.list] say that
the implicit conversion sequence is a user-defined conversion
sequence, but neither specifies that the second standard
conversion sequence is the identity conversion, as is presumably
intended. This makes ranking by 13.3.3.2 [over.ics.rank]
paragraph 3 bullet 2 unncessarily unclear.

Proposed resolution (February, 2012):

Change 13.3.3.1.5 [over.ics.list] paragraphs 3-4 as follows:

Otherwise, if the parameter is a non-aggregate class X and
overload resolution per 13.3.1.7 [over.match.list] chooses a single
best constructor of X to perform the initialization of an
object of type X from the argument initializer list, the
implicit conversion sequence is a user-defined conversion sequence
with the second standard conversion sequence an identity
conversion. If multiple constructors are viable but none is
better than the others, the implicit conversion sequence is the
ambiguous conversion sequence...

Otherwise, if the parameter has an aggregate type which can be
initialized from the initializer list according to the rules for
aggregate initialization (8.5.1 [dcl.init.aggr]), the implicit
conversion sequence is a user-defined conversion sequence with
the second standard conversion sequence an identity
conversion. [Example:...

1408.
What is “the same aggregate initialization?”

User-defined conversion sequence U1 is a
better conversion sequence than another user-defined conversion
sequence U2 if they contain the same user-defined
conversion function or constructor or aggregate initialization
and the second standard conversion sequence of U1 is
better than the second standard conversion sequence of
U2.

It is not clear what “the same aggregate initialization”
means — does this require that the same aggregate type is the
target type?

Proposed resolution (February, 2012):

Change 13.3.3.2 [over.ics.rank] paragraph 3 bullet 2 as
follows:

Standard conversion sequence S1 is a better
conversion sequence...

User-defined conversion sequence U1 is a better
conversion sequence than another user-defined conversion sequence
U2 if they contain the same user-defined conversion function
or constructor or they initialize the same class in an
aggregate initialization and in either case the second
standard conversion sequence of U1 is better than the second
standard conversion sequence of
U2. [Example:...

1398.
Non-type template parameters of type std::nullptr_t

Although 14.1 [temp.param] paragraph 4 explicitly allows
non-type template parameters of type
std::nullptr_t, they cannot actually be used:
14.3.2 [temp.arg.nontype] paragraph 1 does not allow a
template-argument of type std::nullptr_t, and
paragraph 5 does not describe any conversions from other types to
std::nullptr_t.

Proposed resolution (February, 2012):

Add the following new bullet in 14.3.2 [temp.arg.nontype]
paragraph 1:

Do the two fs declare the same function template? According
to 14.5.6.1 [temp.over.link] paragraph 5,

Two expressions involving template parameters are considered
equivalent if two function definitions containing the expressions
would satisfy the one definition rule (3.2 [basic.def.odr]),
except that the tokens used to name the template parameters may differ
as long as a token used to name a template parameter in one expression
is replaced by another token that names the same template parameter in
the other expression.

The relevant portion of 3.2 [basic.def.odr] paragraph 5 says,

in each definition of D, corresponding names, looked up
according to 3.4 [basic.lookup], shall refer to an entity
defined within the definition of D, or shall refer to the
same entity, after overload resolution (13.3 [over.match]) and
after matching of partial template specialization (14.8.3 [temp.over]), except that a name can refer to a const object with
internal or no linkage if the object has the same literal type in all
definitions of D, and the object is initialized with a
constant expression (5.19 [expr.const]), and the value (but
not the address) of the object is used, and the object has the same
value in all definitions of D

This could be read either way, since overload resolution isn't done
at this point. Either we consider the result of the unqualified name
lookup and say that the expressions aren't equivalent or we need a
new rule for equivalence and merging of dependent calls.

Proposed resolution (December, 2011):

Change 14.5.6.1 [temp.over.link] paragraph 5 as follows:

Two expressions involving template parameters are considered
equivalent if two function definitions containing the
expressions would satisfy the one definition rule (3.2 [basic.def.odr]), except that the tokens used to name the template
parameters may differ as long as a token used to name a template
parameter in one expression is replaced by another token that names
the same template parameter in the other expression. For
determining whether two dependent names (14.6.2 [temp.dep])
are equivalent, only the name itself is considered, not the result of
name lookup in the context of the template. If multiple declarations
of the same function template differ in the result of this name
lookup, the result for the first declaration is used.
[Example:

where the postfix-expression is an
id-expressionunqualified-id, the
id-expressionunqualified-id
denotes a dependent name if

any of the expressions in the expression-list is a pack
expansion (14.5.3 [temp.variadic]),

any of the expressions in the expression-list is a
type-dependent expression (14.6.2.2 [temp.dep.expr]), or

if the unqualified-idof the
id-expression is a
template-id in which any of the template arguments depends on a
template parameter.

if an operand...

Change 14.6.4.2 [temp.dep.candidate] paragraph 1 as follows:

For a function call that depends on a template parameterwhere the postfix-expression is a dependent name,
the candidate functions are found using the usual lookup rules
(3.4.1 [basic.lookup.unqual], 3.4.2 [basic.lookup.argdep],
3.4.3 [basic.lookup.qual]) except that:

For the part of the lookup using unqualified name lookup
(3.4.1 [basic.lookup.unqual]) or qualified name lookup (3.4.3 [basic.lookup.qual]), only function declarations from the template
definition context are found.

For the part of the lookup using associated namespaces
(3.4.2 [basic.lookup.argdep]), only function declarations found in
either the template definition context or the template instantiation
context are found.

If the function name is an unqualified-id and the
call would be ill-formed or would find a better match had the lookup
within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in
all translation units, not just considering those declarations found
in the template definition and template instantiation contexts, then
the program has undefined behavior.

1406.
ref-qualifiers and added parameters of non-static member function templates

If only one of the function templates is a non-static member,
that function template is considered to have a new first
parameter inserted in its function parameter list. The new
parameter is of type “reference to cvA,” where cv are the cv-qualifiers of the function
template (if any) and A is the class of which the function
template is a member. [Note: This allows a non-static member to
be ordered with respect to a nonmember function and for the
results to be equivalent to the ordering of two equivalent
nonmembers. —end note]

The Standard appears to be silent as to whether the
reference is an lvalue or rvalue reference; presumably that should
be determined by the ref-qualifier of the member function,
if any.

Proposed resolution (February, 2012):

Change 14.5.6.2 [temp.func.order] paragraph 3 as follows:

To produce the transformed template, for each type, non-type, or
template template parameter (including template parameter packs
(14.5.3 [temp.variadic]) thereof) synthesize a unique type,
value, or class template respectively and substitute it for each
occurrence of that parameter in the function type of the template. If
only one of the function templates is a non-static member of some
class A, that function template is considered to have a
new first parameter inserted in its function parameter
list. TheGiven cv as the cv-qualifiers of the
function template (if any), the new parameter is of type
“rvalue reference to cvA,” if the optional
ref-qualifier of the function template is &&,
or of type “lvalue reference to cvA”
otherwisewhere cv are the cv-qualifiers of the
function template (if any) and A is the class of which the
function template is a member. [Note:...

The problem here is that there is a combination of an invalid expression
in the immediate context (Y<T>::value) and in the
non-immediate context (within Z<T> when evaluating
Z<T>::value). The Standard does not appear to state
clearly whether this program is well-formed (because the error in the
immediate context causes deduction failure) or ill-formed (because of
the error in the non-immediate context).

Notes from the March, 2011 meeting:

Some members expressed a desire to allow implementations latitude
in whether examples like this should be deduction failure or a
diagnosable error, just as the order of evaluation of arithmetic
operands is largely unconstrained. Others felt that specifying something
like a depth-first left-to-right traversal of the expression or
declaration would be better. Another possibility suggested was to
enforce ordering only at comma operators. No consensus was achieved.

CWG agreed that the arguments should be processed in
left-to-right order. Some popular existing code (e.g., Boost) depends
on this ordering.

Proposed resolution (February, 2012):

Change 14.8.2 [temp.deduct] paragraph 7 as follows:

The substitution occurs in all types and expressions that are used in
the function type and in template parameter declarations. The
expressions include not only constant expressions such as those that
appear in array bounds or as nontype template arguments but also
general expressions (i.e., non-constant expressions) inside
sizeof, decltype, and other contexts that allow
non-constant expressions. The substitution proceeds in lexical
order and stops when a condition that causes deduction to fail is
encountered. [Note: The equivalent substitution
in exception specifications is done only when the function is
instantiated, at which point a program is ill-formed if the
substitution results in an invalid type or expression.
—end note] [Example:

1388.
Missing non-deduced context following a function parameter pack

Presumably 14.8.2.5 [temp.deduct.type] paragraph 5 should include a
bullet for a function parameter or function parameter pack that follows a
function parameter pack.

Proposed resolution (February, 2012):

Change 14.8.2.1 [temp.deduct.call] paragraph 1 as follows:

...For a function parameter pack that does not occur at the end of
the parameter-declaration-list, the type of the parameter pack is a
non-deduced context.When a function parameter pack appears in a
non-deduced context (14.8.2.5 [temp.deduct.type]), the type of that
parameter pack is never deduced. [Example:

It seems clear that the third call is ill-formed because by
the time we get to the second function parameter pack we've
already assumed that T is empty, so deducing anything
for T would be nonsensical. But I don't think this is
expressed anywhere in the standard.

One way to handle this would be to say that a template
parameter pack is not deducible if it is used in a function
parameter pack not at the end of the parameter list.

Template argument deduction is done by comparing the return type
of the conversion function template (call it P; see
8.5 [dcl.init], 13.3.1.5 [over.match.conv], and
13.3.1.6 [over.match.ref] for the determination of that type)
with the type that is required as the result of the conversion
(call it A) as described in 14.8.2.5 [temp.deduct.type].

It would seem that the cross-references should apply to the
determination of the type “required as the result of the
conversion” (i.e., A) instead of the return type
of the conversion function.

Proposed resolution (February, 2012):

Change 14.8.2.3 [temp.deduct.conv] paragraph 1 as follows:

Template argument deduction is done by comparing the return type of
the conversion function template (call it P; see
8.5 [dcl.init], 13.3.1.5 [over.match.conv], and
13.3.1.6 [over.match.ref] for the determination of that
type) with the type that is required as the result of the
conversion (call it A; see 8.5 [dcl.init], 13.3.1.5 [over.match.conv], and 13.3.1.6 [over.match.ref] for the
determination of that type) as described in 14.8.2.5 [temp.deduct.type].

1431.
Exceptions from other than throw-expressions

There are a number of places in the Standard that appear to
assume that exceptions are only thrown by throw-expressions.
Various other constructs, such as dynamic_casts,
typeid, new-expressions, etc., can also throw
exceptions, so a more general term should be coined and applied
in place of throw-expression wherever necessary.

Proposed resolution (February, 2012):

Change 3.7.4.1 [basic.stc.dynamic.allocation] paragraph 3 as follows:

...Any other allocation function that fails to allocate storage shall
indicate failure only by throwing an exception (15.1 [except.throw]) of a type that would match a handler (15.3 [except.handle]) of type std::bad_alloc (18.6.2.1 [bad.alloc]).

Change 3.7.4.1 [basic.stc.dynamic.allocation] paragraph 4 as follows:

...[Note: In particular, a global allocation function is not
called to allocate storage for objects with static storage duration
(3.7.1 [basic.stc.static]), for objects or references with thread
storage duration (3.7.2 [basic.stc.thread]), for objects of type
std::type_info (5.2.8 [expr.typeid]), or for the
copy of an object thrown by a throw expressionan exception
object (15.1 [except.throw]). —end note]

Change 5.2.7 [expr.dynamic.cast] paragraph 9 as follows:

The value of a failed cast to pointer type is the null pointer value
of the required result type. A failed cast to reference type throws
an exception (15.1 [except.throw]) of a type that would
match a handler (15.3 [except.handle]) of typestd::bad_cast (18.7.2 [bad.cast]).

Change 5.2.8 [expr.typeid] paragraph 2 as follows:

...If the glvalue expression is obtained by applying the unary
* operator to a pointer68 and the pointer is a
null pointer value (4.10 [conv.ptr]), the typeid
expression throws thean exception (15.1 [except.throw]) of a type that would match a handler of typestd::bad_typeid exception (18.7.3 [bad.typeid]).

Change 5.3.4 [expr.new] paragraph 7 as follows:

When the value of the expression in a
noptr-new-declarator is zero, the allocation function is called
to allocate an array with no elements. If the value of that
expression is less than zero or such that the size of the allocated
object would exceed the implementation-defined limit, or if the
new-initializer is a braced-init-list for which the number of
initializer-clauses exceeds the number of elements to
initialize, no storage is obtained and the new-expressionterminates by throwingthrows an exception
(15.1 [except.throw]) of a type that would match a
handler (15.3 [except.handle]) of type
std::bad_array_new_length (18.6.2.2 [new.badlength]).

Change 15 [except] paragraph 1 as follows:

...A handler will be invoked only by a throw-expression
invokedthrowing an exception in code executed in the
handler's try block or in functions called from the handler's try
block...

Change 15 [except] paragraph 2 as follows:

A try-block is a statement (Clause 6 [stmt.stmt]). A throw-expression is of type void.
Code that executes a throw-expression is said to
“throw an exception;” code that subsequently gets control
is called a “handler.” [Note:...

Change 15.1 [except.throw] paragraph 1 as follows:

Throwing an exception transfers control to a handler. [Note:
An exception can be thrown from one of the following contexts:
throw-expression (see below), allocation functions
(3.7.4.1 [basic.stc.dynamic.allocation]), dynamic_cast
(5.2.7 [expr.dynamic.cast]), typeid (5.2.8 [expr.typeid]),
new-expression (5.3.4 [expr.new]), and standard
library functions (17.5.1.4 [structure.specifications]). —end
note] An object is passed and the type of that object
determines which handlers can catch it. [Example:...

Change 15.1 [except.throw] paragraph 3 as follows:

A throw-expressionThrowing an exception
copy-initializes (8.5 [dcl.init], 12.8 [class.copy]) a temporary object, called the exception
object, the type of which is determined by removing any top-level
cv-qualifiers from the static type of the operand of
throw and adjusting the type from “array of
T” or “function returning T” to
“pointer to T” or “pointer to function
returning T”, respectively. The temporary is an
lvalue and is used to initialize the variable named in the matching
handler (15.3 [except.handle]). If the type of the
exception object would be an incomplete type or a pointer to an
incomplete type other than (possibly cv-qualified) void the
program is ill-formed. Except for these restrictions and the
restrictions on type matching mentioned in 15.3 [except.handle],
the operand of throw is treated exactly as a function
argument in a call (5.2.2 [expr.call]) or the operand of a
return statement.Evaluating a throw-expression with
an operand throws an exception; the type of the exception object is
determined by removing any top-level cv-qualifiers from the
static type of the operand and adjusting the type from “array of
T” or “function returning T” to
“pointer to T” or “pointer to function
returning T,” respectively.

Change 15.1 [except.throw] paragraph 4 as follows:

...[Note:ana thrown exception
thrown by a throw-expression does not propagate to
other threads unless caught, stored, and rethrown using appropriate
library functions; see 18.8.5 [propagation] and 30.6 [futures]. —end note]

Change 15.1 [except.throw] paragraph 8 as follows:

A throw-expression with no operand rethrows the currently
handled exception (15.3 [except.handle]). The exception is
reactivated with the existing temporaryexception
object; no new temporary exception object is created.
The exception is no longer considered to be caught; therefore, the
value of std::uncaught_exception() will again be
true. [Example:...

Change 15.2 [except.ctor] paragraph 1 as follows:

As control passes from a throw-expressionthe
point where an exception is thrown to a handler, destructors are
invoked for all automatic objects constructed since the try block was
entered...

Change 15.2 [except.ctor] paragraph 3 as follows:

The process of calling destructors for automatic objects constructed
on the path from a try block to a throw-expressionthe point where an exception is thrown is called
“stack unwinding.” If a destructor...

Change 15.3 [except.handle] paragraph 17 as follows:

When the handler declares a non-constantan
object, any changes to that object will not affect the temporary
object that was initialized by execution of the
throw-expressionexception object. When the
handler declares a reference to a non-constantan object, any changes to the referenced object are changes
to the temporary object initialized when the
throw-expression was executedexception object
and will have effect should that object be rethrown.

Change 18.8.3.4 [terminate] paragraph 1 as follows:

Remarks: Called by the implementation when exception handling
must be abandoned for any of several reasons (15.5.1 [except.terminate]), in effect immediately after evaluating the
throw-expression (18.8.3.1 [terminate.handler])throwing the exception. May also be called directly by the
program.

1267.
Rvalue reference types in exception-specifications

The types that may appear in an exception-specification
(15.4 [except.spec] paragraph 2) include rvalue reference types,
although they are excluded as handler types (15.3 [except.handle]
paragraph 1). This appears to have been an oversight.

Proposed resolution (February, 2012):

Change 15.4 [except.spec] paragraph 2 as follows:

...A type denoted in an exception-specification shall not
denote an incomplete type or an rvalue reference type. A
type denoted in an exception-specification shall not denote a
pointer or reference...

1381.
Implicitly-declared special member functions and default nothrow

An implicitly declared special member function (Clause 12 [special]) shall
have an exception-specification. If f is an implicitly declared
default constructor, copy constructor, move constructor,
destructor, copy assignment operator, or move assignment
operator, its implicit exception-specification specifies the
type-idT if and only if T is allowed by the
exception-specification of a function directly invoked by
f's implicit definition; f shall allow all
exceptions if any function it directly invokes allows all
exceptions, and f shall allow no exceptions if every
function it directly invokes allows no exceptions.

It would be clearer if this description made explicit the intent
that special member functions that invoke no other functions are to
allow no exceptions.

Proposed resolution (February, 2012):

Change 15.4 [except.spec] paragraph 14 as follows:

...and f has the exception-specificationnoexcept(true) if every function it directly invokes allows
no exceptions. [Note: It follows that f has the
exception-specificationnoexcept(true) if it invokes
no other functions. —end note] [Example:

However, an identifier-list cannot contain an ellipsis
according to the grammar in 16 [cpp] paragraph 1.

Proposed resolution (February, 2012):

Change 16.3 [cpp.replace] paragraph 12 as follows:

If there is a ...in the identifier-listimmediately preceding the ) in the
function-like macro definition, then the trailing
arguments, including any separating comma preprocessing tokens, are
merged to form a single item: the variable argumentsvariable arguments. The number of arguments so
combined is such that, following merger, the number of arguments is
one more than the number of parameters in the macro definition
(excluding the ...).

Issues with "accepted" Status

Issues with "DRWP" Status

712.
Are integer constant operands of a conditional-expression “used?”

The member shall still be defined in a namespace scope if it is
used in the program...

The definition of “used” is in 3.2 [basic.def.odr]
paragraph 1:

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 a
constant expression (5.19 [expr.const]) and the
lvalue-to-rvalue conversion (4.1 [conv.lval]) is
immediately applied.

According to the current wording of the Standard, this example
requires that S::a and S::b be defined in a
namespace scope. The reason for this is that, according to
5.16 [expr.cond] paragraph 4, the result of this
conditional-expression is an lvalue and the
lvalue-to-rvalue conversion is applied to that, not directly
to the object, so this fails the “immediately applied”
requirement. This is surprising and unfortunate, since only the
values and not the addresses of the static data members are used.
(This problem also applies to the proposed resolution of
issue 696.)

Proposed resolution (August, 2011):

Divide 3.2 [basic.def.odr] paragraph 2 into two paragraphs
and change as follows:

An expression is potentially evaluated unless it is an
unevaluated operand (Clause 5) or a subexpression thereof. The
set of potential results of an expression e is defined
as:

if e is an id-expression
(5.1.1 [expr.prim.general]), the set whose sole member is
e,

if e is a class member access
(5.2.5 [expr.ref]), the set of potential results of the
object expression,

if e is a pointer-to-member expression
(5.5 [expr.mptr.oper]) whose second operand is a constant
expression, the set of potential results of the object
expression,

if e has the form (e1), the set of
potential results of e1,

if e is a glvalue conditional expression
(5.16 [expr.cond]), the union of the sets of potential
results of the second and third operands,

if e is a comma expression
(5.18 [expr.comma]), the set of potential results of the
right operand,

otherwise, the empty set.

A variable x whose name appears as a
potentially-evaluated expression ex is
odr-used unless itx is an
object that satisfies the requirements for appearing in a constant
expression (5.19 [expr.const]) and ex is an
element of the set of potential results of an expression e,
where either the lvalue-to-rvalue conversion (4.1 [conv.lval]) is immediately applied to e, or
e is a discarded-value expression (Clause 5 [expr]). this is odr-used...

[Drafting note: this wording requires S::a to be defined
if it is used in an expression like *&S::a.]

1260.
Incorrect use of term “overloaded” in description of odr-use

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The current wording of 3.2 [basic.def.odr] paragraph 2 uses
the term “overloaded” differently from its definition in
13 [over] paragraph 1. For example, names found by
argument-dependent lookup are not “overloaded” if they are
not declared in the same scope. The phrasing should be reconciled
between the two sections.

Proposed resolution (August, 2011):

Change 3.2 [basic.def.odr] paragraph 2 as follows:

...A non-overloaded function whose name appears as a
potentially-evaluated expression is odr-used if it is the unique
lookup result or it is the selectedor a member of a
set of candidateoverloaded functions
(3.4 [basic.lookup], 13.3 [over.match],
13.4 [over.over]), if selected by overload
resolution when referred to from a potentially-evaluated expression,
is odr-used, unless it is a pure virtual function and its name
is not explicitly qualified...

1362.
Complete type required for implicit conversion to T&

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The requirement in 3.2 [basic.def.odr] paragraph 4 that a
type T must be complete if an expression is implicitly
converted to a pointer to T or reference to T
inadvertently applies to user-defined conversions, although it was
intended only to refer to built-in conversions.

an expression that is not a null pointer constant, and has
type other than cvvoid*, is converted to
the type pointer to T or reference to T using
an implicita standard conversion (Clause
4 [conv]), a dynamic_cast (5.2.7 [expr.dynamic.cast]) or a static_cast (5.2.9 [expr.static.cast]),
or

1352.
Inconsistent class scope and completeness rules

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The rules regarding class scope and when the class is considered to
be complete (normally implemented by deferred parsing of portions of
class member declarations) are inconsistent and need to be clarified.

Proposed resolution (August, 2011):

Change 3.3.7 [basic.scope.class] paragraph 1 as follows:

The potential scope of a name declared in a class consists not
only of the declarative region following the name's point of
declaration, but also of all function bodies, default arguments, andbrace-or-equal-initializers of non-static data members,
and default arguments in that class (including such things in
nested classes).

Change 3.4.1 [basic.lookup.unqual] paragraph 7 as follows:

A name used in the definition of a class X outside of a member
function body, default argument,
brace-or-equal-initializer of a non-static data member,
or nested class definition29 shall be declared in one of
the following ways:...

Change 3.4.1 [basic.lookup.unqual] paragraph 8 as follows:

AFor the members of a class X, a name
used in a member function body, in a default argument, in the
brace-or-equal-initializer of a non-static data member
(9.2 [class.mem]), or in the definition of a
class member function (9.3 [class.mfct]) of
class Xoutside of the definition of
X, following the function'smember'sdeclarator-id [Footnote: That is, an
unqualified name that occurs, for instance, in a type or default
argument in the parameter-declaration-clause or in the
function
bodyexception-specification. —end
footnote],or in the
brace-or-equal-initializer of a non-static data member
(9.2 [class.mem]) of class X shall be declared
in one of the following ways:...

[Drafting note: 9.2 [class.mem] paragraph 2 requires no
changes. 3.3.7 [basic.scope.class] paragraph 1 bullet 5 deals with
out-of-class definitions, and bullet 2 ensures that the lookup results
for argument types are the same for in-class and out-of-class
declarations, so no change is required.]

1003.
Acceptable definitions of main

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The specification of the forms of the definition of main
that an impliementation is required to accept is clear in C99 that
the parameter names and the exact syntactic form of the types can
vary. Although it is reasonable to assume that a C++ implementation
would accept a definition like

int main(int foo, char** bar) { /* ... */ }

instead of the canonical

int main(int argc, char* argv[]) { /* ... */ }

it might be a good idea to clarify the intent using wording
similar to C99's.

Proposed resolution (August, 2011):

Change 3.6.1 [basic.start.main] paragraph 2 as follows:

...All implementations shall
allow both of the following definitions of main:

int main() { /* ... */ }

and

int main(int argc, char* argv[]) { /* ... */ }

function of () returning int
and

function of (int, pointer to pointer to
char) returning int

as the type of main (8.3.5 [dcl.fct]. In the latter form, for purposes of
exposition, the first function parameter is called argc and
the second function parameter is called argv, whereargc shall be the number of arguments...

597.
Conversions applied to out-of-lifetime non-POD lvalues

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

An lvalue referring to an out-of-lifetime non-POD class objects can
be used in limited ways, subject to the restrictions in
3.8 [basic.life] paragraph 6:

if the original object will be or was of a non-POD class type, the
program has undefined behavior if:

the lvalue is used to access a non-static data member or call a
non-static member function of the object, or

the lvalue is implicitly converted (4.10 [conv.ptr])
to a reference to a base class type, or

the lvalue is used as the operand of a static_cast
(5.2.9 [expr.static.cast]) except when the conversion is
ultimately to cvchar& or cvunsigned
char& ), or

the lvalue is used as the operand of a dynamic_cast
(5.2.7 [expr.dynamic.cast]) or as the operand
of typeid.

There are at least a couple of questionable things in this list.
First, there is no “implicit conversion to a reference to a
base class,” as assumed by the second bullet. Presumably
this is intended to say that the lvalue is bound to a reference to
a base class, and the cross-reference should be to
8.5.3 [dcl.init.ref], not to 4.10 [conv.ptr]
(which deals with pointer conversions). However, even given that
adjustment, it is not clear why it is forbidden to bind a reference
to a non-virtual base class of an out-of-lifetime object, as that is
just an address offset calculation. (Binding to a virtual base, of
course, would require access to the value of the object and thus
cannot be done outside the object's lifetime.)

The third bullet also appears questionable. It's not clear why
static_cast is discussed at all here, as the only
permissible static_cast conversions involving reference types
and non-POD classes are to references to base or derived classes and
to the same type, modulo cv-qualification; if implicit
“conversion” to a base class reference is forbidden in the
second bullet, why would an explicit conversion be permitted in the
third? Was this intended to refer to
reinterpret_cast? Also, is there a reason to allow char
types but disallow array-of-char types (which are more likely to be
useful than a single char)?

Proposed resolution (March, 2008):

Change 3.8 [basic.life] paragraph 5 as follows:

...If the object will be or was of a non-trivial class type,
the program has undefined behavior if:

the pointer is used to access a non-static data member or
call a non-static member function of the object, or

the pointer is implicitly converted (4.10 [conv.ptr]) to a pointer to a virtual base class
type, or

the pointer is used as the operand of a static_cast
(5.2.9 [expr.static.cast]) (except when the conversion is
to void*, or to void* and subsequently to
char*, or unsigned char*).pointer to
cvvoid, or to pointer to cvvoid and
subsequently to pointer to cvchar or pointer to
cvunsigned char, or

the pointer is used as the operand of a dynamic_cast
(5.2.7 [expr.dynamic.cast])...

Change 3.8 [basic.life] paragraph 6 as follows:

...if the original object will be or was of a non-trivial
class type, the program has undefined behavior if:

the lvalue is used to access a non-static data member or
call a non-static member function of the object, or

the lvalue is implicitly converted (4.10 [conv.ptr])bound to a reference to a virtual
base class type(8.5.3 [dcl.init.ref]),
or

the lvalue is used as the operand of a
static_cast (5.2.9 [expr.static.cast]) except when the
conversion is ultimately to cvchar& or
cvunsigned char&, or

the lvalue is used as the operand of a
dynamic_cast (5.2.7 [expr.dynamic.cast]) or as the
operand of typeid.

[Drafting notes: Paragraph 5 was changed to track the
changes to paragraph 6. See also the resolution for issue 658.]

483.
Normative requirements on integral ranges

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

There is no normative requirement on the ranges of the integral
types, although the footnote in 3.9.1 [basic.fundamental]
paragraph 2 indicates the intent (for int, at least)
that they match the values given in the <climits>
header. Should there be an explicit requirement of some sort?

(See also paper N1693.)

Proposed resolution (August, 2011):

Change 3.9.1 [basic.fundamental] paragraph 3 as follows:

...collectively called the extended integer types. The
signed and unsigned integral types shall satisfy the constraints given
in ISO C 5.2.4.2.1.

292.
Deallocation on exception in new before arguments evaluated

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to the C++ Standard section 5.3.4 [expr.new]
paragraph 21 it is unspecified whether the allocation function is called before
evaluating the constructor arguments or after evaluating the
constructor arguments but before entering the constructor.

On top of that paragraph 17 of the same section insists that

If any
part of the object initialization described above [Footnote: This may
include evaluating a new-initializer and/or calling a constructor.]
terminates by throwing an exception and a suitable deallocation
function is found, the deallocation function is called to free the
memory in which the object was being constructed... If no unambiguous
matching deallocation function can be found, propagating the exception
does not cause the object's memory to be freed...

Now suppose we have:

An implementation that always evaluates the constructor arguments
first (for a new-expression that creates an object of a class type and
has a new-initializer) and calls the allocation function afterwards.

Here the new-expression '::new copy_throw(0, an_object)' throws an
exception when evaluating the constructor's arguments and before the
allocation function is called. However, 5.3.4 [expr.new]
paragraph 17
prescribes that in such a case the implementation shall call the
deallocation function to free the memory in which the object was being
constructed, given that a matching deallocation function can be found.

So a call to the Standard library deallocation function '::operator
delete(void*)' shall be issued, but what argument is an implementation
supposed to supply to the deallocation function? As per
5.3.4 [expr.new] paragraph 17 - the argument is the address
of the memory in
which the object was being constructed. Given that no memory has yet
been allocated for the object, this will qualify as using an invalid
pointer value, which is undefined behaviour by virtue of
3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 4.

Suggested resolution:

Change the first sentence of 5.3.4 [expr.new] paragraph 17
to read:

If the memory for the object being created has already been
successfully allocated and any part of the object initialization
described above...

Proposed resolution (March, 2008):

Change 5.3.4 [expr.new] paragraph 18 as follows:

If any part of the object initialization described above
[Footnote: ...] terminates by throwing an exception,
storage has been obtained for the object, and a suitable
deallocation function can be found, the deallocation function is
called...

1305.
alignof applied to array of unknown size

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to 5.3.6 [expr.alignof] paragraph 1,

An alignof expression yields the alignment requirement of its
operand type. The operand shall be a type-id representing a
complete object type or an array thereof or a reference to a complete
object type.

This (presumably unintentionally) excludes a reference to an array
with an unknown bound but a complete element type; the bound is not
needed to determine the alignment of the array.

Proposed resolution (August, 2011):

Change 5.3.6 [expr.alignof] paragraph 1 as follows:

An alignof expression yields the alignment requirement of its
operand type. The operand shall be a type-id representing a
complete object type or an array thereof or a reference to a complete
object typeone of those types.

1340.
Complete type in member pointer expressions

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

Both the .* and ->* operators
(5.5 [expr.mptr.oper]) require that the class of the second
operand be a complete object type. Current implementations do not
enforce this requirement, and it is not clear that there is a need
for it.

Proposed resolution (August, 2011):

Change 5.5 [expr.mptr.oper] paragraph 2 as follows:

The binary operator .* binds its second operand, which shall
be of type “pointer to member of T” (where
T is a completely-defined class type) to its first
operand...

Change 5.5 [expr.mptr.oper] paragraph 3 as follows:

The binary operator ->* binds its second operand, which
shall be of type “pointer to member of T”
(where T is a completely-defined class type) to
its first operand...

1293.
String literals in constant expressions

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

It is not clear whether a string literal can be used in a constant
expression.

Proposed resolution (August, 2011):

Change 5.19 [expr.const] paragraph 2 as follows:

an lvalue-to-rvalue conversion (4.1 [conv.lval])
unless it is applied to

a glvalue of integral or enumeration type that refers to a
non-volatile const object with a preceding initialization, initialized
with a constant expression [Note: a string literal
(2.14.5 [lex.string]) corresponds to an array of such
objects. —end note], or

1313.
Undefined pointer arithmetic in constant expressions

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The requirements for constant expressions do not currently,
but should, exclude expressions that have undefined behavior, such as
pointer arithmetic when the pointers do not point to elements of the
same array.

Proposed resolution (August, 2011):

Change 5.19 [expr.const] paragraph 2 as follows:

...

a result that is not mathematically defined or not in the
range of representable values for its type;

an invocation of a constexpr constructor with
arguments that, when substituted by function invocation substitution
(7.1.5 [dcl.constexpr]), do not produce all constant expressions
for the constructor calls and full-expressions in the
mem-initializers (including conversions);
[Example:...

Delete the final bullet of 7.1.5 [dcl.constexpr]
paragraph 3 and move the deleted "." to the preceding
sub-bullet:

every constructor call and implicit conversion used in
initializing the return value (6.6.3 [stmt.return],
8.5 [dcl.init]) shall be one of those allowed in a constant
expression (5.19 [expr.const]).

Delete the final bullet of 7.1.5 [dcl.constexpr]
paragraph 4 and change the preceding bullet as follows:

every assignment-expression that is an
initializer-clause appearing directly or indirectly within a
brace-or-equal-initializer for a non-static data member that is not
named by a mem-initializer-id shall be a constant expression;
and.

every implicit conversion used in converting a constructor
argument to the corresponding parameter type and converting a
full-expression to the corresponding member type shall be one of those
allowed in a constant expression.

1365.
Calling undefined constexpr functions

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The current wording appears to allow calling a constexpr
function that is never defined within the body of a constexpr
function. (The wording was intended to allow mutually-recursive
constexpr functions but require that the not-yet-defined
function be defined before it would be needed in an actual constant
expression.)

1367.
Use of this in a constant expression

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The provisions allowing the use of this in a constant
expression appear to be unnecessary, as any uses of this in
a constant expression that are valid will be replaced by function
invocation substitution.

1366.
Deleted constexpr constructors and virtual base classes

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The requirement that a class with a constexpr constructor
cannot have a virtual base only applies to constructors with
non-deleted and non-defaulted function-bodys. This seems like
an oversight.

Proposed resolution (August, 2011):

Change 7.1.5 [dcl.constexpr] paragraph 4 as follows:

In aThe definition of a constexpr
constructor, each of the parameter types shall be a literal type. In
addition, either its
function-body shall be = delete or = default
or it shall satisfy the following constraints:

the class shall not have any virtual base classes;

each of the parameter types shall be a literal type;

its function-body shall not be a
function-try-block;

In addition, either its function-body shall be
= delete or it shall satisfy the following constraints:

either its function-body shall be = default
or the compound-statement of its function-body shall
contain only...

this (5.1 [expr.prim]5.1.1 [expr.prim.general]) unless it appears as the
postfix-expression in a class member access expression,
including the result of the implicit transformation in the body of a
non-static member function (9.3.1 [class.mfct.non-static])[Note: when evaluating a constant expression, function
invocation substitution (7.1.5 [dcl.constexpr]) replaces each
occurrence of this in a constexpr member function
with a pointer to the class object. —end
note];

539.
Constraints on type-specifier-seq

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The constraints on type-specifiers given in
7.1.6 [dcl.type] paragraphs 2 and 3 (at most one
type-specifier except as specified, at least one
type-specifier, no redundant cv-qualifiers) are couched in
terms of decl-specifier-seqs and declarations. However,
they should also apply to constructs that are not syntactically
declarations and that are defined to use
type-specifier-seqs, including 5.3.4 [expr.new],
6.6 [stmt.jump], 8.1 [dcl.name], and
12.3.2 [class.conv.fct].

Proposed resolution (August, 2011):

Change 7.1.6 [dcl.type] paragraph 3 as follows:

AtExcept in a declaration of a constructor,
destructor, or conversion function, at least one
type-specifier that is not a cv-qualifieris
required in a declaration unless it declares a constructor, destructor
or conversion functionshall appear in a complete
type-specifier-seq or a complete
decl-specifier-seq.92 A
type-specifier-seq shall not define...

(Note: paper N2546, voted into the Working Draft in February,
2008, addresses part of this issue.)

1265.
Mixed use of the auto specifier

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The current wording of 7.1.6.4 [dcl.spec.auto] does not appear
to forbid using the auto specifier for both a function
declaration with a trailing return type and a variable definition in
the same declaration, e.g.,

If the list of declarators contains more than one declarator,
they shall all form declarations of variables. Thethe type of each declared variable is determined as
described above. If, and if the type deduced for
the template parameter U is not the same in each deduction,
the program is ill-formed. [Example:...

1346.
expression-list initializers and the auto specifier

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

7.1.6.4 [dcl.spec.auto] does not address the case when the
initializer for an auto variable is a parenthesized
expression-list.

Proposed resolution (August, 2011):

Change 7.1.6.4 [dcl.spec.auto] paragraph 3 as follows:

...auto shall appear as one of the decl-specifiers in
the decl-specifier-seq and the decl-specifier-seq shall
be followed by one or more init-declarators, each of which
shall have a non-empty initializer. In an initializer of
the form

(expression-list)

the expression-list shall be a single
assignment-expression. [Example:...

1347.
Consistency of auto in multiple-declarator declarations

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The intent of 7.1.6.4 [dcl.spec.auto] paragraph 7 appears to
have been that the type represented by auto should be the
same for each declarator in the declaration. However, the current
wording does not achieve that goal. For example, in

auto a = 0, b = { 1, 2, 2 };

the auto specifier represents int in the
first declarator and std::initializer_list<int>
in the second. (See also issue 1265.)

Proposed resolution (August, 2011):

Move the example in 7.1.6.4 [dcl.spec.auto] paragraph 7 into
that of paragraph 6 and change paragraph 7 as follows:

The type of i is the deduced type of the parameter
u in the call f(expr) of the following invented
function template:

template <class U> void f(const U& u);

—end example]

If the list of declaratorsinit-declarator-list contains more than one
declaratorinit-declarator, the type of
each declared variable is determined as described above. If the type
deduced for the template parameter Uthat
replaces the occurrence of auto is not the same in each
deduction, the program is ill-formed.

[Example:

const auto &i = expr;

The type of i is the deduced type of the parameter
u in the call f(expr) of the following invented
function template:

7.3.3 [namespace.udecl] paragraph 13 does not appear to apply
because it deals only with functions, not function templates:

If a function declaration in namespace scope or block scope has the
same name and the same parameter types as a function introduced by a
using-declaration, and the declarations do not declare the same
function, the program is ill-formed.

John Spicer: For function templates I believe the rule
should be that if they have the same function type (parameter types
and return type) and have identical template parameter lists, the
program is ill-formed.

Proposed resolution (August, 2011):

Change 7.3.3 [namespace.udecl] paragraph 14 as follows:

If a function declaration in namespace scope or block scope has the
same name and the same parameter typesparameter-type-list (8.3.5 [dcl.fct]) as a
function introduced by a using-declaration, and the
declarations do not declare the same function, the program is
ill-formed. If a function template declaration in namespace
scope has the same name, parameter-type-list, return type, and
template parameter list as a function template introduced by a
using-declaration, the program is ill-formed.
[Note: Two using-declarations may introduce functions
with the same name and the same parameter typesparameter-type-list. If, for a call to an unqualified
function name, function overload resolution selects the functions
introduced by such using-declarations, the function call is
ill-formed. [Example:...

1297.
Misplaced function attribute-specifier

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

There is a contradiction between the grammar of 8 [dcl.decl]
paragraph 4 and that of 8.3.5 [dcl.fct] paragraphs 1 and 2 and
8.4.1 [dcl.fct.def.general] paragraph 2 regarding the placement of the
optional exception-specification: in the former, it immediately
follows the parameter-declaration-clause, while in the latter it
follows the exception-specification.

482.
Qualified declarators in redeclarations

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to 8.3 [dcl.meaning] paragraph 1,

A declarator-id shall not be qualified except for the
definition of a member function (9.3 [class.mfct]) or
static data member (9.4 [class.static]) outside of its
class, the definition or explicit instantiation of a function or
variable member of a namespace outside of its namespace, or the
definition of a previously declared explicit specialization
outside of its namespace, or the declaration of a friend function
that is a member of another class or namespace (11.3 [class.friend]). When the declarator-id is qualified, the
declaration shall refer to a previously declared member of the
class or namespace to which the qualifier refers...

There doesn't seem to be any good reason for disallowing such
declarations, and a number of implementations accept them in
spite of the Standard's prohibition. Should the Standard be
changed to allow them?

Notes from the April, 2006 meeting:

In discussing issue 548, the CWG agreed
that the prohibition of qualified declarators inside their namespace
should be removed.

Proposed resolution (October, 2006):

Remove the indicated words from 8.3 [dcl.meaning]
paragraph 1:

...An unqualified-id occurring in a declarator-id shall
be a simple identifier except for the declaration of some
special functions (12.3 [class.conv], 12.4 [class.dtor], 13.5 [over.oper]) and for the declaration of
template specializations or partial specializations (). A declarator-id shall not be qualified
except for the definition of a member function (9.3 [class.mfct]) or static data member (9.4 [class.static])
outside of its class, the definition or explicit instantiation of a
function or variable member of a namespace outside of its namespace,
or the definition of a previously declared explicit specialization
outside of its namespace, or the declaration of a friend function that
is a member of another class or namespace (11.3 [class.friend]). When the declarator-id is qualified, the
declaration shall refer to a previously declared member of the class
or namespace to which the qualifier refers, and the member shall not
have been introduced by a using-declaration in the scope of the
class or namespace nominated by the nested-name-specifier of
the declarator-id...

[Drafting note: The omission of “outside of its
class” here does not give permission for redeclaration of
class members; that is still prohibited by 9.2 [class.mem]
paragraph 1. The removal of the enumeration of the kinds of
declarations in which a qualified-id can appear does allow
a typedef declaration to use a qualified-id, which
was not permitted before; if that is undesirable, the prohibition can
be reinstated here.]

332.
cv-qualified void parameter types

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

8.3.5 [dcl.fct]/2 restricts the use of void
as parameter type, but does not
mention CV qualified versions. Since void f(volatile void)
isn't a callable
function anyway, 8.3.5 [dcl.fct]
should also ban cv-qualified versions.
(BTW, this follows C)

Suggested resolution:

A possible resolution would be to add (cv-qualified) before void in

The parameter list (void) is equivalent to the empty
parameter list. Except
for this special case, (cv-qualified)void shall
not be a parameter type (though types derived from void, such as
void*, can).

577.
void in an empty parameter list

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

8.3.5 [dcl.fct] paragraph 2 says,

The parameter list (void) is equivalent to the empty
parameter list.

This special case is intended for C compatibility, but C99 describes
it differently (6.7.5.3 paragraph 10):

The special case of an unnamed parameter of type void as the
only item in the list specifies that the function has no parameters.

The C99 formulation allows typedefs for void, while C++
(and C90) accept only the keyword itself in this role. Should the
C99 approach be adopted?

Notes from the October, 2006 meeting:

The CWG did not take a formal position on this issue; however,
there was some concern expressed over the treatment of function
templates and member functions of class templates if the C++ rule
were changed: for a template parameter T, would a function
taking a single parameter of type T become a no-parameter
function if it were instantiated with T = void?

Proposed resolution (August, 2011):

Change 8.3.5 [dcl.fct] paragraph 4 as follows:

...If the parameter-declaration-clause is empty, the function
takes no arguments. The parameter list (void)A parameter list consisting of a single unnamed parameter of
non-dependent type void is equivalent to thean empty parameter list. Except for this special case,
a parameter shall not have type cvvoidshall not be a parameter type (though types derived from
void, such as void*, can). If the
parameter-declaration-clause terminates...

1327.
virt-specifier in a defaulted definition

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The grammar for defaulted and deleted functions in
8.4.2 [dcl.fct.def.default] and 8.4.3 [dcl.fct.def.delete] does not
provide for virt-specifiers. Is there a reason for this
omission, or was it inadvertent?

1333.
Omission of const in a defaulted copy constructor

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

Paragraph 1 of 8.4.2 [dcl.fct.def.default] allows an explicitly-defaulted
copy constructor or copy assignment operator to have a parameter type
that is a reference to non-const, even if the corresponding
implicitly-declared function would have a reference to const. However,
paragraph 2 says that a copy constructor or copy assignment operator that
is defaulted on its first declaration, the parameter type must be exactly
the same. Is there a good reason for the stricter rule for a function
that is defaulted on its first declaration?

Proposed resolution (August, 2011):

Change 8.4.2 [dcl.fct.def.default] paragraph 2 as follows:

...If a function is explicitly defaulted on its first declaration,

...

in the case of a copy constructor, move constructor, copy
assignment operator, or move assignment operator, it shall have the
same parameter type as if it had been implicitly
declared.

Change 12.8 [class.copy] paragraph 12 as follows:

A copy/move constructor for class X is trivial if it is not
user-provided, its declared parameter type is the same as if it
had been implicitly declared, and if...

Change 12.8 [class.copy] paragraph 25 as follows:

A copy/move assignment operator for class X is trivial if it is not
user-provided, its declared parameter type is the same as if it
had been implicitly declared, and if...

1355.
Aggregates and “user-provided” constructors

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The definition of “user-provided” given in
8.4.2 [dcl.fct.def.default] paragraph 4 applies only to special
member functions, while the definition of an aggregate in
8.5.1 [dcl.init.aggr] paragraph 1 relies on that term in
identifying constructors that make a class a non-aggregate. As
a result, a class with a non-special constructor is considered
an aggregate.

Proposed resolution (August, 2011):

Change 8.4.2 [dcl.fct.def.default] paragraph 4 as follows:

A special member function is user-provided if it is
user-declared and not explicitly defaulted or deleted on its first
declaration...

[Drafting note: This makes a class with only a deleted
initializer-list constructor an aggregate.]

1093.
Value-initializing non-objects

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

8.5 [dcl.init] paragraph 7 only describes how to
initialize objects:

To value-initialize an object of type T means:

However, 5.2.3 [expr.type.conv] paragraph 2 calls for
value-initializing prvalues, which in the case of scalar types
are not objects:

The expression T(), where T is a
simple-type-specifier or typename-specifier
for a non-array complete object type or the (possibly
cv-qualified) void type, creates a prvalue of the
specified type, which is value-initialized (8.5 [dcl.init]; no initialization is done for the
void() case).

Proposed resolution (August, 2011):

Change 5.2.3 [expr.type.conv] paragraph 2 as follows:

The expression T(), where T is a
simple-type-specifier or typename-specifier for a
non-array complete object type or the (possibly cv-qualified)
void type, creates a prvalue of the specified type,which
is value-initialized (8.5 [dcl.init]type, whose
value is that produced by value-initializing (8.5 [dcl.init]) an object of type T; no initialization is
done for the void() case). [Note:...

1301.
Value initialization of union

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to 8.5 [dcl.init] paragraph 7,

To value-initialize an object of type T means:

if T is a (possibly cv-qualified) class type
(Clause 9 [class]) with a user-provided constructor
(12.1 [class.ctor]), then the default constructor for
T is called (and the initialization is ill-formed if
T has no accessible default constructor);

if T is a (possibly cv-qualified) non-union class type
without a user-provided constructor, then the object is
zero-initialized and, if T's implicitly-declared default
constructor is non-trivial, that constructor is called.

if T is an array type, then each element is
value-initialized;

otherwise, the object is zero-initialized.

This suggests that for

struct A { A() = delete; };
union B { A a };
int main()
{
B();
}

a B temporary is created and zero-initialized, even though
its default constructor is deleted. We should strike "non-union" and
also the "if...non-trivial" condition, since we can have a trivial
deleted constructor.

Proposed resolution (August, 2011):

Change 8.5 [dcl.init] paragraph 7 as follows:

To value-initialize an object of type T means:

if T is a (possibly cv-qualified) class type
(Clause 9 [class]) with either no default
constructor (12.1 [class.ctor]) or a default
constructor that is user-provided or deletedconstructor (12.1 [class.ctor]), then the
object is default-initializeddefault constructor for
T is called (and the initialization is ill-formed if
T has no accessible default constructor);

if T is a (possibly cv-qualified) non-union class type
without a user-provided or deleted default constructor,
then the object is zero-initialized and, if T's
implicitly-declared default constructor isT has
a non-trivial default constructor, that
constructor is called.default-initialized;

...

Change 8.5.4 [dcl.init.list] paragraph 3 as follows:

List-initialization of an object or reference of type T is
defined as follows:

If the initializer list has no elements and T
is a class type with a default constructor, the object is
value-initialized.

Otherwise, ifIfT is an
aggregate, aggregate initialization is performed (8.5.1 [dcl.init.aggr]). [Example:...

Otherwise, if the initializer list has no elements and
T is a class type with a default constructor, the object is
value-initialized.

1288.
Reference list initialization

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

One might expect that in an example like

int i;
int & ir{i};

ir would bind directly to i. However, according
to 8.5.4 [dcl.init.list] paragraph 3, this example creates a
temporary of type int and binds the reference to that
temporary:

...

Otherwise, if T is a reference type, a prvalue
temporary of the type referenced by T is list-initialized,
and the reference is bound to that temporary...

Otherwise, if the initializer list has a single element, the
object or reference is initialized from that element...

Also, the “or reference” in the last bullet is dead
code, as a reference initialization is always handled by the preceding
bullet.

Proposed resolution (August, 2011):

Change 8.5.4 [dcl.init.list] paragraph 3 as follows:

...

Otherwise, if T is a class type, constructors are
considered...

Otherwise, if T is a reference type, a prvalue
temporary of the type referenced by T is list-initialized,
and the reference is bound to that temporary. [Note: As usual,
the binding will fail and the program is ill-formed if the reference
type is an lvalue reference to a non-const type. —end
note] [Example: ... —end
example]

Otherwise, if the initializer list has a single element of
type E and either T is not a reference type or its
referenced type is reference-related to E, the object
or reference is initialized from that element; if a narrowing
conversion (see below) is required to convert the element to
T, the program is ill-formed. [Example:...

Otherwise, if T is a reference type, a prvalue
temporary of the type referenced by T is list-initialized,
and the reference is bound to that temporary. [Note: As usual,
the binding will fail and the program is ill-formed if the reference
type is an lvalue reference to a non-const type. —end
note] [Example: ... —end
example]

1308.
Completeness of class type within an exception-specification

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to 9.2 [class.mem] paragraph 2,

A class is considered a completely-defined object type (3.9 [basic.types]) (or complete type) at the closing } of the
class-specifier. Within the class member-specification,
the class is regarded as complete within function bodies, default
arguments, exception-specifications, and
brace-or-equal-initializers for non-static data members
(including such things in nested classes). Otherwise it is regarded
as incomplete within its own class member-specification.

With the advent of the noexcept operator, treating the
class type as complete in exception-specifications is obviously
not possible, e.g.,

A class is considered a completely-defined object type (3.9 [basic.types]) (or complete type) at the closing } of the
class-specifier. Within the class member-specification,
the class is regarded as complete within function bodies, default
arguments, exception-specifications, and
brace-or-equal-initializers for non-static data members
(including such things in nested classes). Otherwise it is regarded
as incomplete within its own class member-specification.

Change 15.4 [except.spec] paragraph 2 as follows:

...A type denoted in an exception-specification shall not
denote an incomplete type other than a class currently being
defined. A type denoted in an
exception-specification shall not denote a pointer or reference
to an incomplete type, other than cvvoid*, const void*, volatile void*, or
const volatile void*or a pointer or reference to
a class currently being defined. A type cvT,
“array of T”, or “function returning
T” denoted in an exception-specification is
adjusted to type T, “pointer to T”, or
“pointer to function returning T”, respectively.

1357.
brace-or-equal-initializers for function and typedef members

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

The grammar allows a brace-or-equal-initializer for any
class member with a member-declarator, including typedef
members and member function declarations, and there is no semantic
restriction forbidding those forms, either.

A member can be initialized using a constructor; see 12.1 [class.ctor]. [Note: See Clause 12 [special] for a
description of constructors and other special member functions.
—end note]

A member can be initialized using abrace-or-equal-initializershall appear only in the
declaration of a data member. (For static data members, see
9.4.2 [class.static.data]; for non-static data members, see
12.6.2 [class.base.init]).

1306.
Modifying an object within a const member function

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to 9.3.2 [class.this] paragraph 2,

In a const member function, the object for which the function
is called is accessed through a const access path; therefore,
a const member function shall not modify the object and its
non-static data members.

This is clearly overstating the case: mutable members can
be modified, a const_cast can be used, and class member
access expressions not involving this can also allow the
object to be modified. The effect of the cv-qualification of a member
function on the type of *this is clear from the preceding
paragraph; this statement appears both unnecessary and incorrect.

Proposed resolution (August, 2011):

Merge 9.3.2 [class.this] paragraphs 1 and 2 and change
the text as follows:

In the body of a non-static (9.3 [class.mfct]) member
function, the keyword this is a prvalue expression whose
value is the address of the object for which the function is called.
The type of this in a member function of a class X
is X*. If the member function is declared const,
the type of this is const X*, if the member function
is declared volatile, the type of this is
volatile X*, and if the member function is declared const
volatile, the type of this is const volatile
X*. In[Note: thus in a
const member function, the object for which the function is
called is accessed through a const access path; therefore, a
const member function shall not modify the object and its
non-static data members. —end note]
[Example:...

If the class type in the covariant return type of
D::f differs from the return typethat
of B::f, the class type in the return type of D::f
shall be complete at the point of declaration of D::f or
shall be the class type D. When the overriding function...

Should binding a reference to the result of a "," operation
whose second operand is a temporary extend the lifetime of the
temporary?

const SFileName &C = ( f(), SFileName("abc") );

Notes from the March 2004 meeting:

We think the temporary should be extended.

Proposed resolution (October, 2004):

Change 12.2 [class.temporary] paragraph 2 as
indicated:

... In all these cases, the temporaries created during the
evaluation of the expression initializing the reference, except
the temporary that is the overall result of the expression
[Footnote: For example, if the expression is a comma
expression (5.18 [expr.comma]) and the value of its
second operand is a temporary, the reference is bound to that
temporary.] and to which the reference is bound, are destroyed at
the end of the full-expression in which they are created and in
the reverse order of the completion of their construction...

The CWG suggested a different approach from the 10/2004 resolution,
leaving 12.2 [class.temporary] unchanged and adding normative
wording to 5.18 [expr.comma] specifying that, if the result
of the second operand is a temporary, that temporary is the result of
the comma expression as well.

Proposed Resolution (November, 2006):

Add the indicated wording to 5.18 [expr.comma] paragraph 1:

... The type and value of the result are the type and value of the
right operand; the result is of the same value category as its right
operand, and is a bit-field if its right operand is a glvalue and a
bit-field. If the value of the right operand is a temporary
(12.2 [class.temporary]), the result is that temporary.

535.
Copy construction without a copy constructor

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

Footnote 112 (12.8 [class.copy] paragraph 2) says,

Because a template constructor is never a copy constructor, the
presence of such a template does not suppress the implicit declaration
of a copy constructor. Template constructors participate in overload
resolution with other constructors, including copy constructors, and a
template constructor may be used to copy an object if it provides a
better match than other constructors.

However, many of the stipulations about copy construction are
phrased to refer only to “copy constructors.” For
example, 12.8 [class.copy] paragraph 14 says,

A program is ill-formed if the copy constructor...
for an object is implicitly used and the special member
function is not accessible (clause 11 [class.access]).

Does that mean that using an inaccessible template constructor
to copy an object is permissible, because it is not a “copy
constructor?” Obviously not, but each use of the term
“copy constructor” in the Standard should be examined
to determine if it applies strictly to copy constructors or to
any constructor used for copying. (A similar issue applies to
“copy assignment operators,” which have the same
relationship to assignment operator function templates.)

Proposed Resolution (August, 2011):

Change 3.2 [basic.def.odr] paragraph 2 as follows:

...[Note: This covers calls to named functions (5.2.2 [expr.call]), operator overloading (Clause 13 [over]),
user-defined conversions (12.3.2 [class.conv.fct]), allocation
function for placement new (5.3.4 [expr.new]), as well as
non-default initialization (8.5 [dcl.init]). A copy
constructor or move constructor selected to copy or move an
object of class type is odr-used even if the call is actually
elided by the implementation (12.8 [class.copy]). —end note] ... A
copy-assignment function for a classAn assignment operator
function in a class is odr-used by an implicitly-defined
copy-assignment or move-assignment function for another
class as specified in 12.8 [class.copy]. A move-assignment
function for a class is odr-used by an implicitly-defined
move-assignment function for another class as specified in
12.8 [class.copy]. A default constructor...

Delete 12.1 [class.ctor] paragraph 9:

A copy constructor (12.8 [class.copy]) is used to copy
objects of class type. A move constructor (12.8 [class.copy])
is used to move the contents of objects of class type.

Change 12.2 [class.temporary] paragraph 1 as follows:

...[Note:even if there is no call to the destructor or
copy/move constructor, all the semantic restrictions, such as
accessibility (Clause 11 [class.access]) and whether the
function is deleted (8.4.3 [dcl.fct.def.delete]), shall be
satisfied.this includes accessibility (11 [class.access]) and whether it is deleted, for the constructor selected
and for the destructor. However, in the special case of a
function call...

Change 12.8 [class.copy] paragraph 13 as follows:

A copy/move constructor that is defaulted and not defined as deleted
is implicitly defined if it is odr-used (3.2 [basic.def.odr])
to initialize an object of its class type from a copy of an
object of its class type or of a class type derived from its class
type [Footnote: See 8.5 [dcl.init] for more details
on direct and copy initialization. —end footnote]
or when it is explicitly defaulted...

Change 12.8 [class.copy] paragraph 31 as follows:

When certain criteria are met, an implementation is allowed to omit
the copy/move construction of a class object, even if the
copy/move constructor selected for the copy/move
operation and/or the destructor for the object have
side effects...

Change 13.3.3.1.2 [over.ics.user] paragraph 4 as follows:

A conversion of an expression of class type to the same class type is
given Exact Match rank, and a conversion of an expression of class
type to a base class of that type is given Conversion rank, in spite
of the fact that a copy/move constructor (i.e., a
user-defined conversion function) is called for those cases.

Change 15.1 [except.throw] paragraph 3 as follows:

A throw-expressioncopy-initializes
(8.5 [dcl.init]) a temporary object, called the
exception object...

Change 15.1 [except.throw] paragraph 5 as follows:

When the thrown object is a class object, the copy/move
constructor selected for the copy-initialization and the
destructor shall be accessible, even if the copy/move operation is
elided (12.8 [class.copy]).

1350.
Incorrect exception specification for inherited constructors

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to 12.9 [class.inhctor] paragraph 3, the exception
specification for an inheriting constructor has the same exception
specification as the inherited constructor. This ignores the
exception specifications of default constructors for base classes
and nonstatic data members and of functions called in
brace-or-equals-initializers of nonstatic data members.

Proposed resolution (August, 2011):

Delete the indicated bullet of 12.9 [class.inhctor]
paragraph 2:

the exception-specification (15.4 [except.spec]),

Change 12.9 [class.inhctor] paragraph 3 as follows:

...[Note: Default arguments are not inherited. An
exception-specification is implied as specified in 15.4 [except.spec]. —end note]

Change 15.4 [except.spec] paragraph 14 as follows:

An inheriting constructor (12.9 [class.inhctor]) and
an implicitly declared special member function (Clause
12 [special]) shall have an exception-specification.
If f is an inheriting constructor or an implicitly
declared default constructor, copy constructor, move constructor,
destructor, copy assignment operator, or move assignment operator, its
implicit exception-specification specifies the type-idT if and only if T is allowed by the
exception-specification of a function directly invoked by
f's implicit definition; f shall allow all
exceptions if any function it directly invokes allows all exceptions,
and f shall allow no exceptions if every function it directly
invokes allows no exceptions. [Note: an instantiation of
an inheriting constructor template has an implied
exception-specification as if it were a non-template inheriting
constructor. —end note] [Example:...

This is not correct. Because of the special deduction rule for
rvalue reference parameters in 14.8.2.1 [temp.deduct.call] paragraph
3 and the reference-collapsing rules of 8.3.2 [dcl.ref]
paragraph 6, the parameter type for both will be void(&)().

In fact, U can be deduced to an empty sequence by
14.8.1 [temp.arg.explicit] paragraph 3:

A trailing template parameter pack (14.5.3 [temp.variadic]) not
otherwise deduced will be deduced to an empty sequence of template
arguments.

Proposed resolution (August, 2011):

Change 14.1 [temp.param] paragraph 11 as follows:

...A template parameter pack of a function template shall not be
followed by another template parameter unless that template parameter
can be deduced from the parameter-type-list of the
function template or has a default argument (14.8.2 [temp.deduct]). [Example:

1296.
Ill-formed template declarations (not just definitions)

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

According to 14.6 [temp.res] paragraph 8,

Knowing which names are type names allows the syntax of every template
definition to be checked. No diagnostic shall be issued for a
template definition for which a valid specialization can be generated.
If no valid specialization can be generated for a template definition,
and that template is not instantiated, the template definition is
ill-formed, no diagnostic required. If every valid specialization of
a variadic template requires an empty template parameter pack, the
template definition is ill-formed, no diagnostic required. If a type
used in a non-dependent name...

It seems that these points could and should apply to template
declarations that are not definitions, as well.

Proposed resolution (August, 2011):

Change 14.6 [temp.res] paragraph 8 as follows:

Knowing which names are type names allows the syntax of every template
definition to be checked. No diagnostic shall be issued
for a template definition for which a valid specialization
can be generated. If no valid specialization can be generated for a
template definition, and that template is not instantiated,
the template definition is ill-formed, no diagnostic
required. If every valid specialization of a variadic template
requires an empty template parameter pack, the template
definition is ill-formed, no diagnostic required. If a
type used...

1262.
Default template arguments and deduction failure

[Voted into the WP at the February, 2012 meeting;
moved to DR at the October, 2012 meeting.]

Proposed resolution (August, 2011):

Change 14.8.2 [temp.deduct] paragraph 5 as follows:

The resulting substituted and adjusted function type is used as the
type of the function template for template argument deduction. If a
template argument has not been deduced, its default template
argument, if any, is usedand its corresponding template
parameter has a default argument, the template argument is determined
by substituting the template arguments determined for preceding
template parameters into the default argument. If the substitution
results in an invalid type, as described above, type deduction
fails. [Example:...

EDG, g++, and Sun all catch the original (unmodified) value. Microsoft
catches the modified value. In some sense the EDG/g++/Sun behavior makes
sense because the later catch could catch the derived class instead of the
base class, which would be difficult to do if you let the catch clause
update the value to be used by a subsequent catch.

But on this non-pointer case, all of the compilers later catch the
modified value:

Should "base*const&" be able to catch a "derived*"?
The current standard
seems to say "no" but parallels to how calls work, and existing practice,
suggest that the answer should be "yes".

Should "base*&" be able to catch a "derived*". Again,
the standard seems
seems to say "no". Parallels to how calls work still suggest "no", but
existing practice suggests "yes".

If either of the above is "yes", what happens if you modify the pointer
referred to by the reference. This requires a cast to remove const for
case #2.

On a related front, if you catch
"derived*&" when a "derived*" is thrown,
what happens if you modify the pointer referred to by the reference?
EDG/g++/Sun still don't modify the underlying value that would be
caught by a rethrow in this case. This case seems like it should be
the same as the "int&" example above, but is not on the three compilers
mentioned.

The consensus of the CWG was that it should not be possible to catch
a pointer to a derived class using a reference to a base class pointer,
and that a handler that takes a reference to non-const pointer should
allow the pointer to be modified by the handler.

Proposed resolution (March, 2010):

Change 15.3 [except.handle] paragraph 3 as follows:

A handler is a match for an exception object of type
E if

The handler is of type cvT or
cvT& and E and T are the
same type (ignoring the top-level cv-qualifiers), or

the handler is of type cvT or
cvT& and T is an unambiguous public
base class of E, or

the handler is of type cv1T*cv2or const
T& where T is a pointer type and E is
a pointer type that can be converted to the type of the
handlerT by either or both of

a standard pointer conversion (4.10 [conv.ptr]) not involving conversions to pointers to private or
protected or ambiguous classes

a qualification conversion

the handler is of type cvT or const T& where T is a pointer or pointer to member type
and E is std::nullptr_t.

can f() return 2? That is, does an
int* exception object match a const int*&
handler?

According to 15.3 [except.handle] paragraph 3, it does not:

A handler is a match for an exception object of type
E if

The handler is of type cvT or cvT& and E and T are the same type
(ignoring the top-level cv-qualifiers), or

the handler is of type cvT or cvT& and T is an unambiguous public base class of
E, or

the handler is of type cv1T*cv2 and
E is a pointer type that can be converted to the type of the
handler by either or both of

a standard pointer conversion (4.10 [conv.ptr]) not
involving conversions to pointers to private or protected or ambiguous
classes

a qualification conversion

the handler is a pointer or pointer to member type and
E is std::nullptr_t.

Only the third bullet allows qualification conversions, but
only the first bullet applies to a handler of
reference-to-pointer type. This is consistent with how other
reference bindings work; for example, the following is ill-formed:

int* p;
const int*& r = p;

(The consistency is not complete; the reference binding would be
permitted if r had type const int* const &, but
a handler of that type would still not match an int*
exception object.)

However, implementation practice seems to be in the other
direction; both EDG and g++ do match an int* with a const
int*&, and the Microsoft compiler issues an error for the
presumed hidden handler in the code above. Should the Standard be
changed to reflect existing practice?

The problem is 15.4 [except.spec] paragraph 14 only says that
the exception-specification of C::~C “shall allow
no exceptions,” which could mean either throw() or
noexcept(true).

Proposed resolution (August, 2011):

Change 15.4 [except.spec] paragraph 14 as follows:

An implicitly declared special member function (Clause 12 [special]) shall havehas an
exception-specification. If f is an implicitly
declared default constructor, copy constructor, move constructor,
destructor, copy assignment operator, or move assignment operator, its
implicit exception-specification specifies the type-idT
if and only if T is allowed by the
exception-specification of a function directly invoked by
f's implicit definition; fshall allowallows all exceptions if any function it directly invokes
allows all exceptions, and fshall allow no
exceptionshas the exception-specificationnoexcept(true) if every function it directly invokes
allows no exceptions. [Example:

Issues with "WP" Status

Issues with "CD1" Status

663.
Valid Cyrillic identifier characters

The C99 and C++ Standards disagree about the validity of two
Cyrillic characters for use in identifiers. C++ (_N2691_.E [extendid]) says that 040d is valid in an identifier but that 040e is
not; C99 (Annex D) says exactly the opposite. In fact, both
characters should be accepted in identifiers; see
the
Unicode chart.

Proposed resolution (February, 2008):

The reference in paragraph 2 should be changed to ISO/IEC TR 10176:2003
and the table should be changed to conform to the one in that document
(beginning on page 34).

357.
Definition of signature should include name

Section 1.3 [intro.defs], definition of "signature"
omits the function name as part of the signature. Since the name participates
in overload resolution, shouldn't it be included in the definition?
I didn't find a definition of signature in the ARM,
but I might have missed it.

Fergus Henderson:
I think so. In particular, 17.6.4.3.2 [global.names]
reserves certain "function
signatures" for use by the implementation, which would be wrong
unless the signature includes the name.

-2- Each global function signature declared with external linkage in a
header is reserved to the implementation to designate that function
signature with external linkage.

-5- Each function signature from the Standard C library declared with
external linkage is reserved to the implementation for use as a
function signature with both extern "C" and extern "C++" linkage,
or as a name of namespace scope in the global namespace.

Other uses of the term "function signature" in the description of the
standard library also seem to assume that it includes the name.

James Widman:

Names don't participate in overload resolution; name lookup is
separate from overload resolution. However, the word
“signature” is not used in clause 13 [over].
It is used in linkage and declaration matching (e.g.,
14.5.6.1 [temp.over.link]). This suggests that the name
and scope of the function should be part of its signature.

Proposed resolution (October, 2006):

Replace 1.3 [intro.defs] “signature”
with the following:

the name and the parameter-type-list (8.3.5 [dcl.fct])
of a function, as well as the class or namespace of which it is a
member. If a function or function template is a class member its
signature additionally includes the cv-qualifiers (if any) on
the function or function template itself. The signature of a function
template additionally includes its return type and its template
parameter list. The signature of a function template specialization
includes the signature of the template of which it is a specialization
and its template arguments (whether explicitly specified or deduced).
[Note: Signatures are used as a basis for name-mangling and
linking. —end note]

Delete paragraph 3 and replace the first sentence of
14.5.6.1 [temp.over.link] as follows:

The signature of a function template specialization consists of the
signature of the function template and of the actual template
arguments (whether explicitly specified or deduced).

The signature of a function template consists of its function
signature, its return type and its template parameter listis
defined in 1.3 [intro.defs]. The names
of the template parameters are significant...

537.
Definition of “signature”

The standard defines “signature” in two places:
1.3 [intro.defs] and 14.5.6.1 [temp.over.link]
paragraphs 3-4. The former seems to be meant as a formal definition
(I think it's the only place covering the nontemplate case), yet it
lacks some bits mentioned in the latter (specifically, the notion of a
“signature of a function template,” which is part of every
signature of the associated function template specializations).

Also, I think the 1.3 [intro.defs] words “the
information about a function that participates in overload
resolution” isn't quite right either. Perhaps, “the
information about a function that distinguishes it in a set of
overloaded functions?”

Eric Gufford:

In 1.3 [intro.defs] the definition states that
“Function signatures do not include return type, because that
does not participate in overload resolution,” while 14.5.6.1 [temp.over.link] paragraph 4 states “The signature of a
function template consists of its function signature, its return type
and its template parameter list.” This seems inconsistent and
potentially confusing. It also seems to imply that two identical
function templates with different return types are distinct
signatures, which is in direct violation of 13.3 [over.match]. 14.5.6.1 [temp.over.link] paragraph 4 should be
amended to include verbiage relating to overload resolution.

Either return types are included in function signatures, or they're
not, across the board. IMHO, they should be included as they are an
integral part of the function declaration/definition irrespective of
overloads. Then verbiage should be added about overload resolution to
distinguish between signatures and overload rules. This would help
clarify things, as it is commonly understood that overload
resolution is based on function signature.

In short, the term “function signature” should be made
consistent, and removed from its (implicit, explicit or otherwise)
linkage to overload resolution as it is commonly understood.

James Widman:

The problem is that (a) if you say the return type is part of the
signature of a non-template function, then you have overloading but
not overload resolution on return types (i.e., what we have now with
function templates). I don't think anyone wants to make the language
uglier in that way. And (b) if you say that the return type is not
part of the signature of a function template, you will break code.
Given those alternatives, it's probably best to maintain the status
quo (which the implementors appear to have rendered faithfully).

513.
Non-class “most-derived” objects

The standard uses “most derived object” in some places
(for example, 1.3 [intro.defs] “dynamic
type,” 5.3.5 [expr.delete]) to refer to objects of
both class and non-class type. However, 1.8 [intro.object] only
formally defines it for objects of class type.

an object of a most derived class type is called a most derived object

to

an object of a most derived class type, or of non-class type, is called
a most derived object

Proposed resolution (October, 2005):

Add the indicated words to 1.8 [intro.object] paragraph 4:

If a complete object, a data member (9.2 [class.mem]), or
an array element is of class type, its type is considered the most
derived class, to distinguish it from the class type of any base
class subobject; an object of a most derived class type, or of a
non-class type, is called a most derived object.

637.
Sequencing rules and example disagree

In 1.9 [intro.execution] paragraph 16, the following expression is
still listed as an example of undefined behavior:

i = ++i + 1;

However, it appears that the new sequencing rules make this expression
well-defined:

The assignment side-effect is required to be sequenced
after the value computations of both its LHS and RHS
(5.17 [expr.ass] paragraph 1).

The LHS (i) is an lvalue, so its value
computation involves computing the address
of i.

In order to value-compute the RHS (++i + 1), it is necessary to
first value-compute the lvalue expression ++i and then do an
lvalue-to-rvalue conversion on the result. This guarantees that the
incrementation side-effect is sequenced before the computation of the
addition operation, which in turn is sequenced before the assignment
side effect. In other words, it yields a well-defined order and final
value for this expression.

It should be noted that a similar expression

i = i++ + 1;

is still not well-defined, since the incrementation side-effect remains
unsequenced with respect to the assignment side-effect.

It's unclear whether making the expression in the example
well-defined was intentional or just a coincidental byproduct of
the new sequencing rules. In either case either the example
should be fixed, or the rules should be changed.

Clark Nelson: In my opinion, the poster's argument is
perfectly correct. The rules adopted reflect the CWG's desired
outcome for issue 222. At the Portland
meeting, I presented (and still sympathize with) Tom Plum's case
that these rules go a little too far in nailing down required
behavior; this is a consequence of that.

One way or another, a change needs to be made, and I think we
should seriously consider weakening the resolution of issue 222 to keep this example as having
undefined behavior. This could be done fairly simply by having
the sequencing requirements for an assignment expression depend
on whether it appears in an lvalue context.

James Widman: How's this for a possible re-wording?

In all cases, the side effect of the assignment expression is
sequenced after the value computations of the right and left
operands. Furthermore, if the assignment expression appears in a
context where an lvalue is required, the side effect of the
assignment expression is sequenced before its value computation.

Notes from the February, 2008 meeting:

There was no real support in the CWG for weakening the resolution
of issue 222 and returning the example to
having undefined behavior. No one knew of an implementation that
doesn't already do the (newly) right thing for such an example, so
there was little motivation to go out of our way to increase the
domain of undefined behavior. So the proposed resolution is to change
the example to one that definitely does have undependable behavior in
existing practice, and undefined behavior under the new rules.

Also, the new formulation of the sequencing rules approved in
Oxford contained the wording that by and large resolved issue 222, so with the resolution of this issue, we
can also close issue 222.

Proposed resolution (March, 2008):

Change the example in 1.9 [intro.execution] paragraph 16 as
follows:

i = v[i++]; // the behavior is undefined
i = 7, i++, i++; //i becomes 9
i = ++ii++ + 1; // the behavior is undefined
i = i + 1; // the value of i is incremented

If a side effect on a scalar object is unsequenced relative to
either a different side effect on the same scalar object or a
value computation using the value of the same scalar object, the
behavior is undefined.

It's not clear to me whether the two side-effects in n=--n
are “different.” As far as I can tell, it seems that both
side-effects involve the assignment of -1 to n, which in a sense
makes them non-“different.” But I don't know if that's the
intent. Would it be better to say “another” instead of
“a different?”

...If a side effect on a scalar object is unsequenced
relative to either a differentanother side effect
on the same scalar object or a value computation using the value
of the same scalar object, the behavior is
undefined. [Example:

362.
Order of initialization in instantiation units

Should this program do what its author obviously expects? As far as
I can tell, the standard says that the point of instantiation for
Fib<n-1>::Value is the same as the point of instantiation as the
enclosing specialization, i.e., Fib<n>::Value. What in the standard
actually says that these things get initialized in the right order?

John Spicer:
My opinion is that the standard does not specify
the behavior of this program.
I thought there was a core issue related to this, but I could not find it.
The issue that I recall proposed tightening up the static initialization
rules to make more cases well defined.

Your comment about point of instantiation is correct, but I don't think that
really matters. What matters is the order of execution of the initialization
code at execution time. Instantiations don't really live in
"translation units"
according to the standard. They live in "instantiation units", and the
handling of instantiation units in initialization is unspecified (which should
probably be another core issue). See 2.2 [lex.phases]
paragraph 8.

Notes from October 2002 meeting:

We discussed this and agreed that we really do mean the the order
is unspecified. John Spicer will propose wording on handling of
instantiation units in initialization.

Proposed resolution (April 2003):

TC1 contains the following text in 3.6.2 [basic.start.init]
paragraph 1:

Objects with static storage duration defined in namespace scope in the
same translation unit and dynamically initialized shall be initialized
in the order in which their definition appears in the translation
unit.

Dynamic initialization of an object is either ordered or unordered.
Explicit specializations and definitions
of class template static data members have ordered
initialization. Other class template static data member instances have
unordered initialization. Other objects defined in namespace scope
have ordered initialization. Objects defined within a single
translation unit and with ordered initialization shall be initialized
in the order of their definitions in the translation unit. The order
of initialization is unspecified for objects with unordered
initialization and for objects defined in different translation units.

This addresses this issue but while reviewing this issue some
additional changes were suggested for the above wording:

Dynamic initialization of an object is either ordered or unordered.
Definitions of explicitly specializedExplicit specializations and definitions of
class template static data members have ordered
initialization. Other class template static data members (i.e.,
implicitly or explicitly instantiated specializations)instances have
unordered initialization. Other objects defined in namespace scope
have ordered initialization. Objects defined within a single
translation unit and with ordered initialization shall be initialized
in the order of their definitions in the translation unit. The order
of initialization is unspecified for objects with unordered
initialization and for objects defined in different translation units.

558.
Excluded characters in universal character names

C99 and C++ differ in their approach to universal character
names (UCNs).

Issue 248 already covers the differences
in UCNs allowed for identifiers, but a more fundamental issue is that
of UCNs that correspond to codes reserved by ISO 10676 for surrogate
pair forms.

Specifically, C99 does not allow UCNs whose short names
are in the range 0xD800 to 0xDFFF. I think C++ should
have the same constraint. If someone really wants to
place such a code in a character or string literal,
they should use a hexadecimal escape sequence instead,
for example:

505.
Conditionally-supported behavior for unknown character escapes

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.

309.
Linkage of entities whose names are not simply identifiers, in introduction

3 [basic] paragraph 8, while not incorrect, does not
allow for linkage of operators and conversion functions. It says:

An identifier used in more than one translation unit can potentially
refer to the same entity in these translation units depending on the
linkage (3.5 [basic.link]) of the identifier specified in each
translation unit.

485.
What is a “name”?

A name is a use of an identifier (2.11 [lex.name])
that denotes an entity or label (6.6.4 [stmt.goto],
6.1 [stmt.label]).

Just three paragraphs later, it says

Two names are the same if

they are identifiers composed of the same character sequence;
or

they are the names of overloaded operator functions formed with
the same operator; or

they are the names of user-defined conversion functions formed
with the same type.

The last two bullets contradict the definition of name
in paragraph 4 because they are not identifiers.

This definition affects other parts of the Standard, as well.
For example, in 3.4.2 [basic.lookup.argdep] paragraph 1,

When an unqualified name is used as the postfix-expression
in a function call (5.2.2 [expr.call]), other
namespaces not considered during the usual unqualified lookup
(3.4.1 [basic.lookup.unqual]) may be searched, and in those
namespaces, namespace-scope friend function declarations
(11.3 [class.friend]) not otherwise visible may be found.

With the current definition of name, argument-dependent
lookup apparently does not apply to function-notation calls to
overloaded operators.

Another related question is whether a template-id is a
name or not and thus would trigger an argument-dependent lookup.
Personally, I have always viewed a template-id as a name,
just like operator+.

A name is a use of
an identifieridentifier (2.11 [lex.name]), operator-function-id (13.5 [over.oper]), conversion-function-id (12.3.2 [class.conv.fct]), or template-id (14.2 [temp.names])
that denotes an entity or label (6.6.4 [stmt.goto],
6.1 [stmt.label]). A variable is introduced by the
declaration of an object. The variable’s name denotes the object.

Every name that denotes an entity is introduced by a
declaration. Every name that denotes a label is introduced
either by a goto statement (6.6.4 [stmt.goto]) or
a labeled-statement (6.1 [stmt.label]).

A variable is introduced by the
declaration of an object. The variable's name denotes the
object.

Some names denote types, classes,
enumerations, or templates. In general, it is necessary to
determine whether or not a name denotes one of these entities before
parsing the program that contains it. The process that determines this
is called name lookup (3.4 [basic.lookup]).

Two names are the same if

they are identifiersidentifiers composed
of the same character sequence; or

they are the names of overloaded operator functionsoperator-function-ids formed with the same operator;
or

they are the names of user-defined conversion functionsconversion-function-ids formed with the same
type., or

they are template-ids that refer to the same class
or function (14.4 [temp.type]).

An identifierA name used in more than one
translation unit can potentially refer to the same entity in these
translation units depending on the linkage (3.5 [basic.link])
of the identifiername specified in each translation
unit.

Change 3.3.7 [basic.scope.class] paragraph 1 item 5 as follows:

The potential scope of a declaration that extends to or past the end
of a class definition also extends to the regions defined by its
member definitions, even if the members are defined lexically outside
the class (this includes static data member definitions, nested class
definitions, member function definitions (including the member
function body and any portion of the declarator part of such
definitions which follows
the identifierdeclarator-id, including a
parameter-declaration-clause and any default arguments
(8.3.6 [dcl.fct.default]).

[Drafting note: This last change is not really mandated by the
issue, but it's another case of “identifier” confusion.]

261.
When is a deallocation function "used?"

3.2 [basic.def.odr] paragraph 2 says that a deallocation
function is "used" by a new-expression or
delete-expression appearing in a potentially-evaluated
expression. 3.2 [basic.def.odr] paragraph 3 requires only that
"used" functions be defined.

This wording runs afoul of the typical implementation technique for
polymorphic delete-expressions in which the deallocation
function is invoked from the virtual destructor of the most-derived
class. The problem is that the destructor must be defined, because
it's virtual, and if it contains an implicit reference to the
deallocation function, the deallocation function must also be defined,
even if there are no relevant new-expressions or
delete-expressions in the program.

Is it required that D::operator delete(void*) be defined,
even if no B or D objects are ever created or
deleted?

Suggested resolution: Add the words "or if it is found by
the lookup at the point of definition of a virtual destructor
(12.4 [class.dtor])" to the specification in 3.2 [basic.def.odr] paragraph 2.

Notes from 04/01 meeting:

The consensus was in favor of requiring that any declared
non-placement operator delete member function be
defined if the destructor for the class is defined (whether
virtual or not), and similarly for a non-placement
operator new if a constructor is defined.

Proposed resolution (10/01):

In 3.2 [basic.def.odr] paragraph 2, add the indicated text:

An allocation or deallocation function for a class is
used by a new expression appearing in a potentially-evaluated
expression as specified in 5.3.4 [expr.new]
and 12.5 [class.free].
A deallocation function for a class is used by a delete expression
appearing in a potentially-evaluated expression as specified in
5.3.5 [expr.delete] and 12.5 [class.free].
A non-placement allocation or deallocation function for a
class is used by the definition of a constructor of that class. A
non-placement deallocation function for a class is used by the
definition of the destructor of that class, or by being selected by
the lookup at
the point of definition of a virtual destructor (12.4 [class.dtor]).
[Footnote: An implementation is not required to call
allocation and deallocation functions from constructors or
destructors; however, this is a permissible implementation
technique.]

Does (1) introduce U as a visible name in the surrounding
namespace scope?

If not, then (2) could presumably be an error since the
"union U" in that definition does not find the same type
as the declaration (1).

If yes, then (3) is OK too. However, we have gone through
much trouble to allow template implementations that do not
pre-parse the template definitions, but requiring (1) to
be visible would change that.

There was consensus that example 1 should be allowed.
(Compilers already parse declarations in templates; even MSVC++ 6.0
accepts this case.) The vote was 7-2.

Example 2, on the other hand, is wrong; the union name goes
into a block scope anyway.

Proposed resolution:

In 3.3.2 [basic.scope.pdecl]
change the second bullet of paragraph 5 as follows:

for an elaborated-type-specifier of the form

class-key identifier

if the elaborated-type-specifier is used in the
decl-specifier-seq or parameter-declaration-clause
of a function defined in namespace scope, the identifier is declared
as a class-name in the namespace that contains the
declaration; otherwise, except as a friend declaration, the identifier
is declared in the smallest non-class, non-function-prototype scope
that contains the declaration. [Note: These rules also apply within
templates.] [Note: ...]

Most (all?) compilers reject this code because
D is handled as a template name rather than as
the injected class name.

9 [class]/2 says that the injected class
name is "inserted into the scope of the class."

3.3.7 [basic.scope.class]/1 seems to be the text
intended to describe
what "scope of a class" means, but it assumes that
every name in that scope was introduced using a
"declarator". For an implicit declaration such
as the injected-class name it is not clear what
that means.

So my questions:

Should the injected class name be available
in the base class specifiers?

John Spicer:
I do not believe the injected class name should be available in the base
specifier. I think the semantics of injected class names should be as
if a magic declaration were inserted after the opening "{" of the class
definition. The injected class name is a member of the class and
members don't exist at the point where the base specifiers are scanned.

Do you agree the wording should be clarified
whatever the answer to the first question?

John Spicer:
I believe the 3.3.7 [basic.scope.class] wording should be
updated to reflect the fact that not all names come from declarators.

1) The potential scope of a name declared in a class consists not only of the
declarative region following the name's point of declarationdeclarator,
but also of all function
bodies, default arguments, and constructor ctor-initializers
in that class (including such things in nested classes).
The point of declaration of an injected-class-name
(clause 9 [class]) is
immediately following the opening brace of the class definition.

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:

143.
Friends and Koenig lookup

When an unqualified name is used as the postfix-expression
in a function call
(5.2.2 [expr.call]
)... namespace-scope
friend function declarations
(11.3 [class.friend]
) not otherwise
visible may be found... the set of declarations found
by the lookup of the function name [includes] the set
of declarations found in the... classes associated with
the argument types.

The most straightforward reading of this wording is that if a function of
namespace scope (as opposed to a class member function) is
declared as a friend in a class, and that class is an
associated class in a function call, the friend function will
be part of the overload set, even if it is not visible to
normal lookup.

This example would seem to satisfy the criteria from
3.4.2 [basic.lookup.argdep]
:
A::S is an associated class of the argument, and
A::S has a
friend declaration of the namespace-scope function
B::f(A::S),
so Koenig lookup should include B::f(A::S) as part of the
overload set in the call.

Another interpretation is that, instead of finding the friend
declarations in associated classes, one only looks for namespace-scope
functions, visible or invisible, in the namespaces of which the the
associated classes are members; the only use of the friend
declarations in the associated classes is to validate whether an
invisible function declaration came from an associated class or not
and thus whether it should be included in the overload set or not.
By this interpretation, the call f(s) in the example will
fail, because B::f(A::S) is not a member of namespace
A and thus is not found by the lookup.

Notes from 10/99 meeting: The second interpretation
is correct. The wording should be revised to make clear that Koenig
lookup works by finding "invisible" declarations in namespace scope
and not by finding friend declarations in associated
classes.

Proposed resolution (04/01): The "associated classes"
are handled adequately under this interpretation by
3.4.2 [basic.lookup.argdep] paragraph 3, which describes the
lookup in the associated namespaces as including the friend
declarations from the associated classes. Other mentions of the
associated classes should be removed or qualified to avoid the
impression that there is a lookup in those classes:

In 3.4.2 [basic.lookup.argdep], change

When an unqualified name is used as the postfix-expression
in a function call (5.2.2 [expr.call]), other
namespaces not considered during the usual unqualified lookup
(3.4.1 [basic.lookup.unqual]) may be searched, and
namespace-scope friend function declarations
(11.3 [class.friend]) not otherwise visible may be found.

to

When an unqualified name is used as the postfix-expression
in a function call (5.2.2 [expr.call]), other
namespaces not considered during the usual unqualified lookup
(3.4.1 [basic.lookup.unqual]) may be searched, and
in those namespaces,
namespace-scope friend function declarations
(11.3 [class.friend]) not otherwise visible may be found.

In 3.4.2 [basic.lookup.argdep] paragraph 2, delete
the words and classes in the following two sentences:

If the ordinary unqualified lookup of the name finds the
declaration of a class member function, the associated namespaces
and classes are not considered. Otherwise the
set of declarations found by the lookup of the function name is
the union of the set of declarations found using ordinary
unqualified lookup and the set of declarations found in the
namespaces and classes associated with the
argument types.

218.
Specification of Koenig lookup

The original intent of the Committee when Koenig lookup was added
to the language was apparently something like the following:

The name in the function call expression is looked up like any
other unqualified name.

If the ordinary unqualified lookup finds nothing or finds the
declaration of a (non-member) function, function template, or overload
set, argument-dependent lookup is done and any functions found in
associated namespaces are added to the result of the ordinary
lookup.

This approach is not reflected in the current wording of the
Standard. Instead, the following appears to be the status quo:

Lookup of an unqualified name used as the
postfix-expression in the function call syntax always performs
Koenig lookup (3.4.1 [basic.lookup.unqual] paragraph 3).

Unless ordinary lookup finds a class member function, the result
of Koenig lookup always includes the declarations found in associated
namespaces (3.4.2 [basic.lookup.argdep] paragraph 2), regardless of
whether ordinary lookup finds a declaration and, if so, what kind of
entity is found.

The declarations from associated namespaces are not limited to
functions and template functions by anything in 3.4.2 [basic.lookup.argdep]. However, if Koenig lookup results in more than one
declaration and at least one of the declarations is a non-function,
the program is ill-formed (7.3.4 [namespace.udir], paragraph 4;
although this restriction is in the description of the
using-directive, the wording applies to any lookup that spans
namespaces).

John Spicer: Argument-dependent lookup was created to solve
the problem of looking up function names within templates where you
don't know which namespace to use because it may depend on the
template argument types (and was then expanded to permit use in
nontemplates). The original intent only concerned functions. The
safest and simplest change is to simply clarify the existing wording
to that effect.

Bill Gibbons: I see no reason why non-function declarations
should not be found. It would take a special rule to exclude
"function objects", as well as pointers to functions, from
consideration. There is no such rule in the standard and I see no
need for one.

There is also a problem with the wording in 3.4.2 [basic.lookup.argdep] paragraph 2:

If the ordinary unqualified lookup of the name finds the declaration
of a class member function, the associated namespaces and classes are
not considered.

This implies that if the ordinary lookup of the name finds the
declaration of a data member which is a pointer to function or
function object, argument-dependent lookup is still done.

My guess is that this is a mistake based on the incorrect
assumption that finding any member other than a member function would
be an error. I would just change "class member function" to "class
member" in the quoted sentence.

Mike Miller: In light of the issue of "short-circuiting"
Koenig lookup when normal lookup finds a non-function, perhaps it
should be written as "...finds the declaration of a class member, an
object, or a reference, the associated namespaces..."?

Andy Koenig: I think I have to weigh in on the side of
extending argument-dependent lookup to include function objects and
pointers to functions. I am particularly concerned about [function
objects], because I think that programmers should be able to replace
functions by function objects without changing the behavior of their
programs in fundamental ways.

Bjarne Stroustrup: I don't think we could seriously argue
from first principles that [argument-dependent lookup should find only
function declarations]. In general, C++ name lookup is designed to be
independent of type: First we find the name(s), then, we consider
its(their) meaning. 3.4 [basic.lookup] states "The name
lookup rules apply uniformly to all names ..." That is an important
principle.

Thus, I consider text that speaks of "function call" instead of
plain "call" or "application of ()" in the context of koenig lookup an
accident of history. I find it hard to understand how 5.2.2 [expr.call] doesn't either disallow all occurrences of
x(y) where x is a class object (that's clearly not
intended) or requires koenig lookup for x independently of
its type (by reference from 3.4 [basic.lookup]). I suspect
that a clarification of 5.2.2 [expr.call] to mention
function objects is in order. If the left-hand operand of () is a
name, it should be looked up using koenig lookup.

John Spicer: This approach causes otherwise well-formed
programs to be ill-formed, and it does so by making names visible that
might be completely unknown to the author of the program.
Using-directives already do this, but argument-dependent lookup is
different. You only get names from using-directives if you actually
use using-directives. You get names from argument-dependent
lookup whether you want them or not.

This basically breaks an important reason for having namespaces.
You are not supposed to need any knowledge of the names used by a
namespace.

But this example breaks if argument-dependent lookup finds
non-functions and if the translation unit includes the <list>
header somewhere.

This really makes namespaces of questionable value if you still
need to avoid using the same name as an entity in another namespace to
avoid problems like this.

Erwin Unruh: Before we really decide on this topic, we should
have more analysis on the impact on programs. I would also like to see
a paper on the possibility to overload functions with function
surrogates (no, I won't write one). Since such an extension is bound
to wait until the next official update, we should not preclude any
outcome of the discussion.

I would like to have a change right now, which leaves open several
outcomes later. I would like to say that:

Koenig lookup will find non-functions as well. If it finds a variable, the
program is ill-formed.
If the primary lookup finds a variable, Koenig lookup is done. If the result
contains both functions and variables, the program is ill-formed.
[Note: A future standard will assign semantics to such a program.]

I myself are not comfortable with this as a long-time result, but it
prepares the ground for any of the following long term solutions:

Do overloading on mixed function/variable sets.

Ignore variables on Koenig lookup.

Don't do Koenig lookup if the primary lookup finds a variable.

Find variables on Koenig lookup and give an error if there is a
variable/function mix.

The note is there to prevent compiler vendors to put their own
extensions in here.

Although many agreed that there were valid concerns motivating a
desire for Koenig lookup to find non-function declarations, there was
also concern that supporting this capability would be more dangerous
than helpful in the absence of overload resolution for mixed function
and non-function declarations.

A straw poll of the group revealed 8 in favor of Koenig lookup
finding functions and function templates only, while 3 supported the
broader result.

Notes from the 10/01 meeting:

There was unanimous agreement on one less controversial point:
if the normal lookup of the identifier finds a non-function, argument-dependent
lookup should not be done.

On the larger issue, the primary point of consensus is that making
this change is
an extension, and therefore it should wait until the point at
which we are considering extensions (which could be very soon).
There was also consensus on the fact that the standard as it
stands is not clear: some introductory text suggests that
argument-dependent lookup finds only functions, but the more
detailed text that describes the lookup does not have any
such restriction.

It was also noted that some existing implementations (e.g., g++) do
find some non-functions in some cases.

The issue at this point is whether we should (1) make a small change
to make the standard clear (presumably in the direction of not
finding the non-functions in the lookup), and revisit the issue
later as an extension, or (2) leave the standard alone for now and
make any changes only as part of considering the extension.
A straw vote favored option (1) by a strong majority.

Additional Notes (September, 2006):

Recent discussion of this issue
has emphasized the following points:

The concept of finding function pointers and function objects
as part of argument-dependent lookup is not currently under active
discussion in the Evolution Working Group.

The major area of concern with argument-dependent lookup is
finding functions in unintended namespaces. There are current
proposals to deal with this concern either by changing the
definition of “associated namespace” so that fewer
namespaces are considered or to provide a mechanism for enabling
or disabling ADL altogether. Although this concern is conceptually
distinct from the question of whether ADL finds function pointers
and function objects, it is related in the sense that the current
rules are perceived as finding too many functions (because of
searching too many namespaces), and allowing function pointers
and function objects would also increase the number of entities
found by ADL.

Any expansion of ADL to include function pointers and
function objects must necessarily update the overloading rules
to specify how they interact with functions and function
templates in the overload set. Current implementation experience
(g++) is not helpful in making this decision because, although
it performs a uniform lookup and finds non-function entities, it
diagnoses an error in overload resolution if non-function entities
are in the overload set.

There is a possible problem if types are found by ADL: it
is not clear that overloading between callable entities
(functions, function templates, function pointers, and function
objects) and types (where the postfix syntax means a cast or
construction of a temporary) is reasonable or useful.

James Widman:

There is a larger debate here about whether ADL should find object
names; the proposed wording below is only intended to answer the
request for wording to clarify the status quo (option 1 above) and
not to suggest the outcome of the larger debate.

Proposed Resolution (October, 2006):

Replace the normative text in 3.4.2 [basic.lookup.argdep]
paragraph 3 with the following (leaving the text
of the note and example unchanged):

Let X be the lookup set produced by unqualified lookup
(3.4.1 [basic.lookup.unqual]) and let Y be the lookup set
produced by argument dependent lookup (defined as follows). If X
contains

a declaration of a class member, or

a block-scope function declaration that is not
a using-declaration, or

a declaration that is neither a function nor a function template

then Y is empty. Otherwise Y is the set of declarations
found in the namespaces associated with the argument types as
described below. The set of declarations found by the lookup of
the name is the union of X and Y.

Change 3.4.1 [basic.lookup.unqual] paragraph 4 as
indicated:

When considering an associated namespace, the lookup is the same
as the lookup performed when the associated namespace is used as
a qualifier (3.4.3.2 [namespace.qual]) except that:

Any using-directives in the associated namespace are
ignored.

Any namespace-scope friend functions or friend function
templates declared in associated classes are visible within their
respective namespaces even if they are not visible during an
ordinary lookup (11.3 [class.friend]).

All names except those of (possibly overloaded) functions
and function templates are ignored.

403.
Reference to a type as a template-id

If T is a template-id, its associated namespaces and classes are the
namespace in which the template is defined; for member templates,
the member template's class; the namespaces and classes associated
with the types of the template arguments provided for template type
parameters (excluding template template parameters); the namespaces
in which any template template arguments are defined; and the
classes in which any member templates used as template template
arguments are defined. [Note: non-type template arguments do not
contribute to the set of associated namespaces. ]

There is a problem with the term "is a template-id". template-id
is a syntactic construct and you can't really talk about a type being a
template-id. Presumably, this is intended to mean "If T is the type of a
class template specialization ...".

557.
Does argument-dependent lookup cause template instantiation?

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:

If T is a class type (including unions), its associated
classes are: the class itself; the class of which it is a member, if
any; and its direct and indirect base classes. Its associated
namespaces are the namespaces in which its associated classes are
defined.

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:

If T is a class template specialization its
associated namespaces and classes are the namespace in which the
template is defined; for member templates, the member template’s
class; the namespaces and classes associated with the types of the
template arguments provided for template type parameters (excluding
template template parameters); the namespaces in which any template
template arguments are defined; and the classes in which any member
templates used as template template arguments are
defined.

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:

If T is a class type (including unions), its associated
classes are: the class itself; the class of which it is a member, if
any; and its direct and indirect base classes. Its associated
namespaces are the namespaces inof which its associated
classes are definedmembers. Furthermore,
if T is a class template specialization, its associated
namespaces and classes also include: the namespaces and classes
associated with the types of the template arguments provided for
template type parameters (excluding template template parameters); the
namespaces of which any template template arguments are members; and
the classes of which any member templates used as template template
arguments are members. [Note: Non-type template arguments do not
contribute to the set of associated namespaces. —end
note]

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

If T is a class template specialization its associated
namespaces and classes are the namespace in which the template is
defined; for member templates, the member template’s class; the
namespaces and classes associated with the types of the template
arguments provided for template type parameters (excluding template
template parameters); the namespaces in which any template template
arguments are defined; and the classes in which any member templates
used as template template arguments are defined. [Note: non-type
template arguments do not contribute to the set of associated
namespaces. —end note]

Suggested answer: Yes. All the compilers I tried accept the test case.

Proposed resolution (10/01):

In 3.4.3.1 [class.qual] paragraph 1 add the indicated text:

If the nested-name-specifier of a qualified-id nominates
a class, the
name specified after the nested-name-specifier is looked up in the
scope of the class (10.2 [class.member.lookup]), except for the cases
listed below. The name shall represent one or more members of that
class or of one of its base classes (clause 10 [class.derived]).
If the class-or-namespace-name of the nested-name-specifier
names a cv-qualified class type, it nominates the underlying class
(the cv-qualifiers are ignored).

Notes from 4/02 meeting:

There is a problem in that class-or-namespace-name does not
include typedef names for cv-qualified class types. See
7.1.3 [dcl.typedef] paragraph 4:

Argument and text removed from proposed resolution
(October 2002):

7.1.3 [dcl.typedef] paragraph 5:

Here's a good question: in this example, should X
be used as a name-for-linkage-purposes (FLP name)?

typedef class { } const X;

Because a type-qualifier is parsed as a
decl-specifier, it isn't possible to declare cv-qualified
and cv-unqualified typedefs for a type in a single declaration.
Also, of course, there's no way to declare a typedef for the
cv-unqualified version of a type for which only a cv-qualified version
has a name.
So, in the above example, if X isn't used as the FLP name,
then there can be no FLP name.
Also note that a FLP name usually represents a parameter type, where
top-level cv-qualifiers are usually irrelevant anyway.

Data points: for the above example, Microsoft uses X as the
FLP name; GNU and EDG do not.

My recommendation: for consistency with the direction we're going on
this issue, for simplicity of description (e.g., "the first
class-name declared by the declaration"), and for (very
slightly) increased utility, I think Microsoft has this right.

If the typedef declaration defines an unnamed class type (or
enum type), the first typedef-name declared by the
declaration to behave that class type
(or enum type)or a cv-qualified version thereof
is used to denote the class type (or enum type) for linkage purposes
only (3.5 [basic.link]).
[Example: ...

Proposed resolution (October 2002):

3.4.4 [basic.lookup.elab] paragraphs 2 and 3:

This sentence is deleted twice:

...
If this name lookup finds a typedef-name, the
elaborated-type-specifier is ill-formed.
...

Note that the above changes are included in
N1376 as part of the resolution of issue 245.

5.1.1 [expr.prim.general] paragraph 7:

This is only a note, and it is at least incomplete (and quite possibly
inaccurate), despite (or because of) its complexity.
I propose to delete it.

...
[Note: a typedef-name that names a class is a
class-name (9.1 [class.name]).
Except as the identifier in the declarator for a constructor
or destructor definition outside of a class
member-specification (12.1 [class.ctor],
12.4 [class.dtor]), a typedef-name
that names a class may be used in a qualified-id to refer to
a constructor or destructor. ]

7.1.3 [dcl.typedef] paragraph 4:

My first choice would have been to make this the primary statement about
the equivalence of typedef-name and class-name,
since the equivalence comes about as a result of a typedef declaration.
Unfortunately, references to class-name point to
9.1 [class.name], so it
would seem that the primary statement should be there instead.
To avoid the possiblity of conflicts in the future, I propose to make
this a note.

[Note:
A typedef-name that names a class type, or a cv-qualified
version thereof, is also a class-name
(9.1 [class.name]).
If a typedef-name is used following the
class-key in an elaborated-type-specifier
(7.1.6.3 [dcl.type.elab]),
or in the class-head of a class declaration (9 [class]),
or is used as the identifier in the declarator for a
constructor or destructor declaration (12.1 [class.ctor],
12.4 [class.dtor]),to identify the subject of an elaborated-type-specifier
(7.1.6.3 [dcl.type.elab]),
class declaration (clause 9 [class]),
constructor declaration (12.1 [class.ctor]),
or destructor declaration (12.4 [class.dtor]),
the program is ill-formed.
]
[Example: ...

7.1.6.3 [dcl.type.elab] paragraph 2:

This is the only remaining (normative) statement that a
typedef-name can't be used in an
elaborated-type-specifier.
The reference to template type-parameter is deleted by the
resolution of issue 283.

...
If the identifier resolves to a typedef-nameor a template type-parameter, the
elaborated-type-specifier is ill-formed.
[Note: ...

8 [dcl.decl] grammar rule declarator-id:

When I looked carefully into the statement of the rule prohibiting a
typedef-name in a constructor declaration, it appeared to me
that this grammar rule (inadvertently?) allows something that's always
forbidden semantically.

declarator-id:

id-expression::opt nested-name-specifieropttype-nameclass-name

9.1 [class.name] paragraph 5:

Unlike the prohibitions against appearing in an
elaborated-type-specifier or constructor or destructor
declarator, each of which was expressed more than once, the prohibition
against a typedef-name appearing in a class-head
was previously stated only in 7.1.3 [dcl.typedef].
It seems to me that that prohibition belongs here instead.
Also, it seems to me important to clarify that a typedef-name
that is a class-name is still a typedef-name.
Otherwise, the various prohibitions can be argued around easily, if
perversely ("But that
isn't a typedef-name, it's a class-name; it says
so right there in 9.1 [class.name].")

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 shall not be used
in an elaborated-type-specifier; see also
7.1.3 [dcl.typedef].as the identifier in a class-head.

12.1 [class.ctor] paragraph 3:

The new nonterminal references are needed to really nail down what we're
talking about here.
Otherwise, I'm just eliminating redundancy.
(A typedef-name that doesn't name a class type is no more
valid here than one that does.)

A typedef-name that names a class is a
class-name (7.1.3 [dcl.typedef]); however, aAtypedef-namethat names a class shall not be
used as the identifierclass-name in the declaratordeclarator-id for a constructor declaration.

12.4 [class.dtor] paragraph 1:

The same comments apply here as to 12.1 [class.ctor].

...
A typedef-name that names a class is a
class-name (7.1.3); however, aAtypedef-namethat names a class shall not be
used as the identifierclass-name
following the ~ in the declarator for a destructor
declaration.

318.
struct A::A should not name the constructor of A

A use of an injected-class-name in an elaborated-type-specifier
should not name the constructor of the class, but rather the class itself,
because in that context we know that we're looking for a type.
See issue 147.

Proposed Resolution (revised October 2002):

This clarifies the changes made in the TC for issue 147.

In 3.4.3.1 [class.qual] paragraph 1a replace:

If the nested-name-specifier nominates a class C, and the name
specified after the nested-name-specifier, when looked up in C, is the
injected class name of C (clause 9 [class]), the name is instead
considered to name the constructor of class C.

with

In a lookup in which the constructor is an acceptable lookup result,
if the nested-name-specifier nominates a class C and the name
specified after the nested-name-specifier, when looked up in C, is the
injected class name of C (clause 9 [class]), the name is
instead considered to name the constructor of class C.
[Note: For example, the constructor is not an acceptable lookup result in an
elaborated type specifier so the constructor would not be used in place
of the injected class name.]

I can't find anything in the standard that says definitively what this
means. 7.3.3 [namespace.udecl] says that a using-declaration shall
name "a member of a base class" -- but here we have two members, the
data member A::i and the class A::i.

Personally, I'd find it more attractive if this code did not work. I'd
like "using A::i" to mean "lookup A::i in the usual way and bind B::i to
that", which would mean that while "i = 3" would be valid in D::f,
"struct i x" would not be. However, if there were no A::i data member,
then "A::i" would find the struct and the code in D::f would be valid.

John Spicer:
I agree with you, but unfortunately the standard committee did not.

I remembered that this was discussed by the committee and that a
resolution was adopted that was different than what I hoped for, but I
had a hard time finding definitive wording in the standard.

I went back though my records and found the paper that proposed a
resolution and the associated committee motion that adopted the
proposed resolution The paper is N0905, and "option 1" from that paper
was adopted at the Stockholm meeting in July of 1996. The resolution
is that "using A::i" brings in everything named i from A.

3.4.3.2 [namespace.qual] paragraph 2 was modified to
implement this resolution, but interestingly
that only covers the namespace case and not the class case. I think
the class case was overlooked when the wording was drafted. A core
issue should be opened to make sure the class case is handled
properly.

Notes from April 2003 meeting:

This is related to issue 11.
7.3.3 [namespace.udecl] paragraph 10 has an example
for namespaces.

Proposed resolution (October 2003):

Add a bullet to the end of 3.4.3.1 [class.qual]
paragraph 1:

the lookup for a name specified in a using-declaration
(7.3.3 [namespace.udecl])
also finds class or enumeration names hidden within the same scope
(3.3.10 [basic.scope.hiding]).

Change the beginning of 7.3.3 [namespace.udecl] paragraph 4 from

A
using-declaration
used as a
member-declaration
shall refer to a member of a base class of the class being defined,
shall refer to a member of an anonymous union that is a member of a base class
of the class being defined, or
shall refer to an enumerator for an enumeration type that is a member of a base
class of the class being defined.

to

In a using-declaration used as a
member-declaration, the nested-name-specifier
shall name a base class of the class being defined. Such a
using-declaration introduces the set of declarations found by member
name lookup (10.2 [class.member.lookup],
3.4.3.1 [class.qual]).

245.
Name lookup in elaborated-type-specifiers

I have some concerns with the description of name lookup for
elaborated type specifiers in 3.4.4 [basic.lookup.elab]:

Paragraph 2 has some parodoxical statements concerning looking up
names that are simple identifers:

If the elaborated-type-specifier refers to an enum-name
and this lookup does not find a previously declared enum-name,
the elaborated-type-specifier is ill-formed. If the
elaborated-type-specifier refers to an [sic]class-name and this lookup does not find a previously declared
class-name... the elaborated-type-specifier is a
declaration that introduces the class-name as described in
3.3.2 [basic.scope.pdecl]."

It is not clear how an elaborated-type-specifier can refer
to an enum-name or class-name given that the lookup does
not find such a name and that class-name and enum-name
are not part of the syntax of an elaborated-type-specifier.

The second sentence quoted above seems to suggest that the name found
will not be used if it is not a class name. typedef-name names
are ill-formed due to the sentence preceding the quote. If lookup
finds, for instance, an enum-name then a new declaration will
be created. This differs from C, and from the enum case, and can have
surprising effects:

Was this really the intent? If this is the case then some more
work is needed on 3.4.4 [basic.lookup.elab]. Note that the
section does not make finding a type template formal ill-formed, as is
done in 7.1.6.3 [dcl.type.elab]. I don't see anything that
makes a type template formal name a class-name. So the example
in 7.1.6.3 [dcl.type.elab] of friend class T; where
T is a template type formal would no longer be ill-formed
with this interpretation because it would declare a new class
T.

As given in N1376=02-0034. Note that the inserts and strikeouts in
that document do not display
correctly in all browsers; <del> --> <strike>
and <ins> --> <b>, and the
similar changes for the closing delimiters,
seem to do the trick.

254.
Definitional problems with elaborated-type-specifiers

The text in 3.4.4 [basic.lookup.elab] paragraph 2 twice
refers to the possibility that an elaborated-type-specifier
might have the form

class-key identifier;

However, the grammar for elaborated-type-specifier does
not include a semicolon.

In both 3.4.4 [basic.lookup.elab] and
7.1.6.3 [dcl.type.elab], the text asserts that an
elaborated-type-specifier that refers to a typedef-name
is ill-formed. However, it is permissible for the form of
elaborated-type-specifier that begins with typename
to refer to a typedef-name.

This problem is the result of adding the typename form
to the elaborated-type-name grammar without changing the
verbiage correspondingly. It could be fixed either by updating the
verbiage or by moving the typename syntax into its own
production and referring to both nonterminals when needed.

(See also issue 180. If this
issue is resolved in favor of a separate nonterminal in the
grammar for the typename forms, the wording in that
issue's resolution must be changed accordingly.)

Notes from 04/01 meeting:

The consensus was in favor of moving the typename
forms out of the elaborated-type-specifier grammar.

141.
Non-member function templates in member access expressions

In a class member access expression
(5.2.5 [expr.ref]
), if the . or
-> token is immediately followed by an identifier
followed by a <, the identifier must be looked up to
determine whether the < is the beginning of a template
argument list
(14.2 [temp.names]
) or a less-than
operator. The identifier is first looked up in the class of the
object expression. If the identifier is not found, it is then looked
up in the context of the entire postfix-expression and shall
name a class or function template.

There do not seem to be any circumstances in which use of a
non-member template function would be well-formed as the
id-expression of a class member access expression.

Proposed Resolution (November, 2006):

Change 3.4.5 [basic.lookup.classref] paragraph 1 as follows:

In a class member access expression (5.2.5 [expr.ref]), if
the . or -> token is immediately followed by an
identifier followed by a <, the identifier must be looked
up to determine whether the < is the beginning of a
template argument list (14.2 [temp.names]) or a less-than
operator. The identifier is first looked up in the class of the object
expression. If the identifier is not found, it is then looked up in
the context of the entire postfix-expression and shall name a
class or function template...

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.

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...

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.andIf 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:

381.
Incorrect example of base class member lookup

The example in 3.4.5 [basic.lookup.classref] paragraph 4
is wrong (see 11.2 [class.access.base] paragraph 5; the cast to the
naming class can't be done) and needs to be corrected.
This was noted when the final version of the algorithm for
issue 39 was checked against it.

Proposed Resolution (October 2003):

Remove the entire note at the end of
3.4.5 [basic.lookup.classref] paragraph 4, including the
entire example.

414.
Multiple types found on destructor lookup

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.

However, the same prohibition was not made for class scope types. Indeed,
3.5 [basic.link] paragraph 5 says:

In addition, a member function, static data member, class or
enumeration of class scope has external linkage if the name of the
class has external linkage.

That allows for:

struct S {
typedef enum { e1 } *MPE;
void mf(MPE) {}
};

My guess is that this is an unintentional consequence of
3.5 [basic.link] paragraph 5, but I would like confirmation
on that.

Proposed resolution:

Change text in 3.5 [basic.link] paragraph 5 from:

In addition, a member function, static data member, class or
enumeration of class scope has external linkage if the name of the
class has external linkage.

to:

In addition, a member function, a static data member, a named class or
enumeration of class scope, or an unnamed class or enumeration defined
in a class-scope typedef declaration such that the class or
enumeration has the typedef name for linkage purposes
(7.1.3 [dcl.typedef]),
has external linkage if the name of the class has external linkage.

Paragraph 8 of Section 3.5 [basic.link] contains the following
sentences: "A name with no linkage shall not be used to declare an
entity with linkage. If a declaration uses a typedef name, it is the
linkage of the type name to which the typedef refers that is
considered."

The problem with this wording is that it doesn't cover cases where the
type to which a typedef-name refers has no name. As a result it's not
clear whether, for example, the following program is well-formed:

My feeling is that the rules for whether or not a typedef-name used in
a declaration shall be treated as having or not having linkage ought
to be modelled after those for dependent types, which are explained in
14.6.2.1 [temp.dep.type].

Add the following text at the end of Paragraph 8 of Section
3.5 [basic.link] and replace the following example:

In case of the type referred to by a typedef declaration not having a name,
the newly declared typedef-name has linkage if and only if its referred type
comprises no names of no linkage excluding local names that are eligible for
appearance in an integral constant-expression (5.19 [expr.const]).
[Note: if the referred
type contains a typedef-name that does not denote an unnamed class, the
linkage of that name is established by the recursive application of this
rule for the purposes of using typedef names in declarations.] [Example:

Paragraph 2 of Section 14.3.1 [temp.arg.type] is inaccurate and
unnecessarily prohibits a few important cases; it 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-parameter."
The inaccuracy stems from the fact that it is not a type but its name that
can have a linkage.

For example based on the current wording of 14.3.1 [temp.arg.type],
the following example is ill-formed.

Replace the whole second paragraph of Section 14.3.1 [temp.arg.type]
with the following wording:

A type whose name does not have a linkage or a type compounded from any such
type shall not be used as a template-argument for a template-parameter. In
case of a type T used as a template type argument not having a name,
T
constitutes a valid template type argument if and only if the name of an
invented typedef declaration referring to T would have linkage;
see 3.5.
[Example:

389.
Unnamed types in entities with linkage

A name with no linkage (notably, the name of a class or enumeration
declared in a local scope (3.3.3 [basic.scope.local])) shall not
be used to declare an entity with linkage.
If a declaration uses a typedef name, it is the linkage of the type
name to which the typedef refers that is considered.

The problem here is that most implementations must generate the same
mangled name
for "f" in two translation units. The quote from the standard above
isn't quite
clear, unfortunately: There is no type name to which the typedef refers.

A related situation is the following:

enum { no, yes } answer;

The variable "answer" is declared as having external linkage, but it is
declared
with an unnamed type. Section 3.5 [basic.link]
talks about the linkage of names, however,
and does therefore not prohibit this. There is no implementation issue
for most
compilers because they do not ordinarily mangle variable names, but I
believe
the intent was to allow that implementation technique.

Finally, these problems are much less relevant when declaring names
with internal
linkage. For example, I would expect there to be few problems with:

typedef struct {} *UP;
static void g(UP);

I recently tried to interpret 3.5 [basic.link] paragraph 8
with the assumption that types with no names
have no linkage. Surprisingly, this resulted in many diagnostics on
variable declarations (mostly like "answer" above).

I'm pretty sure the standard needs clarifying words in this matter, but
which way should it go?

There was agreement that this check is not needed for variables
and functions with extern "C" linkage, and a change there is
desirable to allow use of legacy C headers. The check is also not needed for
entities with internal linkage, but there was no strong sentiment
for changing that case.

We also considered relaxing this requirement for extern "C++"
variables but decided that we did not want to change that case.

We noted that if extern "C" functions are allowed an additional
check is needed when such functions are used as arguments in calls
of function templates. Deduction will put the type of the extern "C"
function into the type of the template instance, i.e., there would
be a need to mangle the name of an unnamed type. To plug that hole
we need an additional requirement on the template created in
such a case.

A name with no linkage (notably, the name of a class or enumeration
declared in a local scope (3.3.3 [basic.scope.local]))
shall not be used to declare an
entity with linkage. If a declaration uses a typedef name, it is
the linkage of the type name to which the typedef refers that is
considered.

to

A type is said to have linkage if and only if

it is a class or enumeration type that is named (or has a name for
linkage purposes (7.1.3 [dcl.typedef]))
and the name has linkage; or

it is a specialization of a class template (14 [temp])
[Footnote: a class template always has external linkage, and
the requirements of 14.3.1 [temp.arg.type]
and 14.3.2 [temp.arg.nontype]
ensure that the template arguments will also have appropriate linkage]; or

it is a fundamental type (3.9.1 [basic.fundamental]); or

it is a compound type (3.9.2 [basic.compound])
other than a class or enumeration,
compounded exclusively from types that have linkage; or

it is a cv-qualified (3.9.3 [basic.type.qualifier])
version of a type that has linkage.

A type without linkage shall not be used as the type of a variable or
function with linkage, unless the variable or function has extern "C"
linkage (7.5 [dcl.link]).
[Note: in other words, a type without linkage contains
a class or enumeration that cannot be named outside
of its translation unit. An entity with external linkage
declared using such a type could not correspond to any other entity
in another translation unit of the program and is thus not permitted.
Also note that classes with linkage may contain members whose types do
not have linkage, and that typedef names are ignored in the determination of
whether a type has linkage.]

Change 14.3.1 [temp.arg.type] paragraph 2 from (note:
this is the wording as updated by issue 62)

The following types shall not be used as a template-argument
for a template type-parameter:

a type whose name has no linkage

an unnamed class or enumeration type that has no name for
linkage purposes (7.1.3 [dcl.typedef])

a cv-qualified version of one of the types in this list

a type created by application of declarator operators to one
of the types in this list

a function type that uses one of the types in this list

to

A type without linkage (3.5 [basic.link])
shall not be used as a template-argument
for a template type-parameter.

Once this issue is ready, issue 319
should be moved back to ready as well.

When a block scope declaration of an entity with linkage is not
found to refer to some other declaration, then that entity is a
member of the innermost enclosing namespace.

The question then is whether N is an “enclosing
namespace” for the local declaration of g()?

Proposed resolution (October 2004):

Add the following text as a new paragraph at the end of
7.3.1 [namespace.def]:

The enclosing namespaces of a declaration are those
namespaces in which the declaration lexically appears, except for
a redeclaration of a namespace member outside its original
namespace (e.g., a definition as specified in 7.3.1.2 [namespace.memdef]). Such a redeclaration has the same enclosing
namespaces as the original declaration. [Example:

270.
Order of initialization of static data members of class templates

The Standard does not appear to address how the rules for order
of initialization apply to static data members of class templates.

Suggested resolution: Add the following verbiage to either
3.6.2 [basic.start.init] or 9.4.2 [class.static.data]:

Initialization of static data members of class templates shall be
performed during the initialization of static data members for the
first translation unit to have static initialization performed for
which the template member has been instantiated. This requirement
shall apply to both the static and dynamic phases of initialization.

Notes from 04/01 meeting:

Enforcing an order of initialization on static data members of
class templates will result in substantial overhead on access to such
variables. The problem is that the initialization be required as the
result of instantiation in a function used in the initialization of a
variable in another translation unit. In current systems, the order of
initialization of static data data members of class templates is not
predictable. The proposed resolution is to state that the order of
initialization is undefined.

Proposed resolution (04/01, updated slightly 10/01):

Replace the following sentence in 3.6.2 [basic.start.init]
paragraph 1:

Objects with static storage duration defined in namespace scope in the
same translation unit and dynamically initialized shall be initialized
in the order in which their definition appears in the translation
unit.

with

Dynamic initialization of an object is either ordered or unordered.
Explicit specializations and definitions
of class template static data members have ordered
initialization. Other class template static data member instances have
unordered initialization. Other objects defined in namespace scope
have ordered initialization. Objects defined within a single
translation unit and with ordered initialization shall be initialized
in the order of their definitions in the translation unit. The order
of initialization is unspecified for objects with unordered
initialization and for objects defined in different translation units.

The sentinel list node is used to represent "nil" (the null pointer
cannot be used with my implementation, for reasons which are immaterial
to this discussion). All of the List's non-static member functions and
constructors depend upon the value of the sentinel. Under the proposed
resolution for issue #270, Lists cannot be safely instantiated before
main() begins, as the sentinel's initialization is "unordered".

(Some readers may propose that I should use the "singleton pattern" in the
List class. This is undesirable, for reasons I shall describe at the
end of this post at the location marked "[*]". For the moment, indulge
me by assuming that "singleton" is not an adequate solution.)

Though this is a particular example from my own experience, I believe it
is representative of a general class of examples. It is common to use
static data members of a class to represent the "distinguished values"
which are important to instances of that class. It is imperative that
these values be initialized before any instances of the class are
created, as the instances depend on the values.

In a comp.std.c++ posting on 28 Jul 2001, Brian McNamara proposes
the following alternative resolution:

Replace the following sentence in 3.6.2 [basic.start.init]
paragraph 1:

Objects with static storage duration defined in namespace scope in
the same translation unit and dynamically initialized shall be
initialized in the order in which their definition appears in the
translation unit.

with

Objects with static storage duration defined in namespace scope
shall be initialized in the order described below.

and then after paragraph 1, add this text:

Dynamic initialization is either ordered or quasi-ordered. Explicit
specializations of class template static data members have ordered
initialization. Other class template static data member instances have
quasi-ordered initialization. All other objects defined in namespace
scope have ordered initialization. The order of initialization is
specified as follows:

Objects that are defined within a single translation unit and
that have ordered initialization shall be initialized in the
order of their definitions in the translation unit.

Objects that are defined only within a single translation unit
and that have quasi-ordered initialization shall also be
initialized in the order of their definitions in the translation
unit -- that is, as though these objects had ordered initialization.

Objects that are defined within multiple translation units (which,
therefore, must have quasi-ordered initialization) shall be
initialized as follows: in exactly one translation unit
(which one is unspecified), the object shall be treated as
though it has ordered initialization; in the other translation
units which define the object, the object will be initialized
before all other objects that have ordered initialization in
those translation units.

For any two objects, "X" and "Y", with static storage duration
and defined in namespace scope, if the previous bullets do not
imply a relationship for the initialization ordering between "X"
and "Y", then the relative initialization order of these objects
is unspecified.

along with a non-normative note along the lines of

[ Note: The intention is that translation units can each be compiled
separately with no knowledge of what objects may be re-defined in
other translation units. Each translation unit can contain a method
which initializes all objects (both quasi-ordered and ordered) as
though they were ordered. When these translation units are linked
together to create an executable program, all of these objects can
be initialized by simply calling the initialization methods (one
from each translation unit) in any order. Quasi-ordered objects
require some kind of guard to ensure that they are not initialized
more than once (the first attempt to initialize such an object
should succeed; any subsequent attempts should simply be ignored). ]

Erwin Unruh replies:
There is a point which is not mentioned with this posting.
It is the cost for implementing the scheme. It requires that each
static template variable is instantiated in ALL translation units
where it is used. There has to be a flag for each of these variables
and this flag has to be checked in each TU where the instantiation
took place.

I would reject this idea and stand with the proposed resolution of
issue 270.

There just is no portable way to ensure the "right" ordering of
construction.

Notes from 10/01 meeting:

The Core Working Group reaffirmed its previous decision.

441.
Ordering of static reference initialization

I have a couple of questions about 3.6.2 [basic.start.init],
"Initialization of
non-local objects." I believe I recall some discussion of
related topics, but I can't find anything relevant in the issues
list.

The first question arose when I discovered that different
implementations treat reference initialization differently.
Consider, for example, the following (namespace-scope) code:

Because "int&" is not a POD type, there is no requirement that it
be initialized before dynamic initialization is performed, and
implementations differ in this regard. Using a function called
during dynamic initialization to print the values of "ip" and
"&ir", I found that g++, Sun, HP, and Intel compilers initialize
ir before dynamic initialization and the Microsoft compiler does
not. All initialize ip before dynamic initialization. I believe
this is conforming (albeit inconvenient :-) behavior.

So, my first question is whether it is intentional that a
reference of static duration, initialized with a reference
constant expression, need not be initialized before dynamic
initialization takes place, and if so, why?

The second question is somewhat broader. As
3.6.2 [basic.start.init] is currently
worded, it appears that there are no requirements on when ir is
initialized. In fact, there is a whole category of objects --
non-POD objects initialized with a constant expression -- for
which no ordering is specified. Because they are categorized as
part of "static initialization," they are not subject to the
requirement that they "shall be initialized in the order in which
their definition appears in the translation unit." Because they
are not POD types, they are not required to be initialized before
dynamic initialization occurs. Am I reading this right?

My preference would be to change
3.6.2 [basic.start.init] paragraph 1 so that 1) references
are treated like POD objects with respect to initialization, and
2) "static initialization" applies only to POD objects and
references. Here's some sample wording to illustrate:

Suggested resolution:

Objects with static storage duration (3.7.1) shall be
zero-initialized (8.5) before any other initialization takes
place. Initializing a reference, or an object of POD
type, of static storage duration with a constant expression
(5.19) is called constant initialization. Together,
zero-initialization and constant initialization are called
static initialization; all other initialization is dynamic
initialization. Static initialization shall be performed
before any dynamic initialization takes place. [Remainder
unchanged.]

Proposed Resolution:

Change 3.6.2 [basic.start.init] paragraph 1 as follows:

Objects with static storage duration (3.7.1) shall be
zero-initialized (8.5) before any other initialization takes
place. Initializing a reference, or an object of POD type, of
static storage duration with a constant expression (5.19) is
called constant initialization. Together,
zero-initialization and constant initialization are
Zero-initialization and initialization with a
constant expression are collectively called static
initialization; all other initialization is dynamic
initialization. Static initialization shall be performed
Objects of POD types (3.9) with static storage
duration initialized with constant expressions (5.19) shall be
initialized before any dynamic initialization takes
place.

688.
Constexpr constructors and static initialization

[Voted into the WP at the September, 2008 meeting (resolution
in paper N2757).]

Given this literal type,

struct X {
constexpr X() { }
};

and this definition,

static X x;

the current specification does not require that x be
statically initialized because it is not “initialized with
a constant expression” (3.6.1 [basic.start.main]
paragraph 1).

Lawrence Crowl:

This guarantee is essential for atomics.

Jens Maurer:

Suggestion:

A reference with static storage duration or an object of literal
type with static storage duration can be initialized with a
constant expression (5.19 [expr.const]) or with a
constexpr constructor; this is called constant initialization.

In addition, there is a need to enforce static initialization
for non-literal types: std::shared_ptr,
std::once_flag, and std::atomic_* all have
nontrivial copy constructors, making them non-literal types.
However, we need a way to ensure that a constexpr constructor
called with constant expressions will guarantee static
initialization, regardless of the nontriviality of the copy
constructor.

Proposed resolution (April, 2008):

Change 3.6.2 [basic.start.init] paragraph 1 as follows:

...A reference with static storage duration and an object of
trivial or literal type with static storage duration can be
initialized with a constant expression (5.19 [expr.const]); thisIf a reference with static storage
duration is initialized with a constant expression (5.19 [expr.const]) or if the initialization of an object with static
storage duration satisfies the requirements for the object being
declared with constexpr (7.1.5 [dcl.constexpr]),
that initialization is called constant
initialization...

Change 6.7 [stmt.dcl] paragraph 4 as follows:

...A local object of trivial or literal type (3.9 [basic.types]) with static storage duration initialized with
constant-expressions is initializedConstant
initialization (3.6.2 [basic.start.init]) of a local entity
with static storage duration is performed before its block is
first entered...

Change 7.1.5 [dcl.constexpr] paragraph 7 as follows:

A constexpr specifier used in an object declaration
declares the object as const. Such an object shall be
initialized, and every expression that appears in its initializer
(8.5 [dcl.init]) shall be a constant expression. Every
implicit conversion used in converting the initializer
expressions and every constructor call used for the
initialization shall be one of those allowed in a constant
expression (5.19 [expr.const])...

Replace 8.5.1 [dcl.init.aggr] paragraph 14 as
follows:

When an aggregate with static storage duration is initialized
with a brace-enclosed initializer-list, if all the member
initializer expressions are constant expressions, and the
aggregate is a trivial type, the initialization shall be done
during the static phase of initialization (3.6.2 [basic.start.init]); otherwise, it is unspecified whether the
initialization of members with constant expressions takes place
during the static phase or during the dynamic phase of
initialization.[Note: The order of initialization
for aggregates with static storage duration is specified in
3.6.2 [basic.start.init] and 6.7 [stmt.dcl].
—end note]

(Note: the change to 3.6.2 [basic.start.init] paragraph 1
needs to be reconciled with the conflicting change in
issue 684.)

28.
'exit', 'signal' and static object destruction

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' ;-)

Proposed Resolution (10/98):

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'.]

Notes (November, 2006):

C89 is slightly contradictory here: It allows any signal handler to
terminate by calling abort, exit,
longjmp, but (for asynchronous signals, i.e. not those
produced by abort or raise) then makes calling any
library function other than signal with the current signal
undefined behavior (C89 7.7.1.1). For synchronous signals, C99 forbids
calls to raise, but imposes no other restrictions. For
asynchronous signals, C99 allows only calls
to abort, _Exit, and signal with the
current signal (C99 7.14.1.1). The current C++ WP refers to
“plain old functions” and “conforming C
programs” (18.10 [support.runtime] paragraph 6).

Proposed Resolution (November, 2006):

Change the footnote in 18.10 [support.runtime] paragraph 6 as
follows:

In particular, a signal handler using exception handling is very
likely to have problems. Also, invoking std::exit may
cause destruction of objects, including those of the standard library
implementation, which, in general, yields undefined behavior in a
signal handler (see 1.9 [intro.execution]).

Any other allocation function that fails to allocate storage shall
only indicate failure by throwing an exception of
class std::bad_alloc (18.6.2.1 [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.4.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.6.2.1 [bad.alloc]) or a
class derived from std::bad_alloca type that would
match a handler (15.3 [except.handle]) of type
std::bad_alloc (18.6.2.1 [bad.alloc]).

348.
delete and user-written deallocation functions

Standard is clear on behaviour of default allocation/deallocation
functions.
However, it is surpisingly vague on requirements to the behaviour
of user-defined deallocation function and an interaction between
delete-expression and deallocation function.
This caused a heated argument on fido7.su.c-cpp newsgroup.

Resume:

It is not clear if user-supplied deallocation function is called from
delete-expr when the operand of delete-expr is the null
pointer (5.3.5 [expr.delete]).
If it is, standard does not specify what user-supplied
deallocation function shall do with
the null pointer operand (18.6.1 [new.delete]).
Instead, Standard uses the term "has no effect", which meaning
is too vague in context given (5.3.5 [expr.delete]).

Argument passed to delete-expression is valid - it is the result
of a call to the non-throwing version of ::new, which has been failed.
5.3.5 [expr.delete] paragraph 1 explicitly prohibit us to pass 0
without having the ::new failure.

Standard does NOT specify whether user-defined deallocation function
should be called in this case, or not.

Specifically, standard says in 5.3.5 [expr.delete] paragraph 2:

...if the value of the operand of delete is the null pointer the operation
has no effect.

Standard doesn't specify term "has no effect".
It is not clear from this context, whether the called deallocation function
is required to have no effect, or delete-expression shall not call
the deallocation function.

If the delete-expression calls the implementation deallocation
function (3.7.4.2 [basic.stc.dynamic.deallocation]),
if the operand of the delete expression is not
the null pointer constant, ...

Why it is so specific on interaction of default deallocation function
and delete-expr?

If "has no effect" is a requirement to the deallocation function,
then it should be stated in 3.7.4.2 [basic.stc.dynamic.deallocation],
or in 18.6.1.1 [new.delete.single] and
18.6.1.2 [new.delete.array],
and it should be stated explicitly.

Furthermore, standard does NOT specify what actions shall
be performed by user-supplied deallocation function if NULL
is given (18.6.1.1 [new.delete.single] paragraph 12):

Required behaviour: accept a value of ptr that is null or that was
returned by an earlier call to the default
operator new(std::size_t)
or operator new(std::size_t, const std::nothrow_t&).

The same corresponds to ::delete[] case.

Expected solution:

Make it clear that delete-expr will not call deallocation function
if null pointer is given (in 5.3.5 [expr.delete]).

Specify what user deallocation function shall do when null is given
(either in 3.7.4.2 [basic.stc.dynamic.deallocation], or
in 18.6.1.1 [new.delete.single], and
18.6.1.2 [new.delete.array]).

Notes from October 2002 meeting:

We believe that study of 18.6.1.1 [new.delete.single] paragraphs
12 and 13, 18.6.1.2 [new.delete.array] paragraphs 11 and 12, and
3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 3 shows that the
system-provided operator delete functions must accept a null pointer and
ignore it. Those sections also show that a user-written replacement
for the system-provided operator delete functions must accept a
null pointer. There is no requirement that such functions ignore
a null pointer, which is okay -- perhaps the reason for replacing the
system-provided functions is to do something special
with null pointer values (e.g., log such calls and return).

We believe that the standard should not require an implementation
to call a delete function with a null pointer, but it must allow
that. For the system-provided delete functions or replacements
thereof, the standard already makes it clear that the delete
function must accept a null pointer. For class-specific delete
functions, we believe the standard should require that such
functions accept a null pointer, though it should not mandate
what they do with null pointers.

5.3.5 [expr.delete] needs to be updated to say that
it is unspecified whether or not the operator delete function is
called with a null pointer, and 3.7.4.2 [basic.stc.dynamic.deallocation]
needs to be updated to say that any deallocation function must
accept a null pointer.

Proposed resolution (October, 2004):

Change 5.3.5 [expr.delete] paragraph 2 as
indicated:

If the operand has a class type, the operand is converted to a
pointer type by calling the above-mentioned conversion function,
and the converted operand is used in place of the original
operand for the remainder of this section. In either alternative,
if the value of the operand of deleteis the
null pointer the operation has no effectmay be a null
pointer value. If it is not a null pointer value, inIn the first alternative (delete object), the value
of the operand of delete shall be a pointer to a
non-array object or a pointer to a sub-object (1.8 [intro.object]) representing a base class of such an object
(clause 10 [class.derived])...

Change 5.3.5 [expr.delete] paragraph 4 as
follows (note that the old wording reflects the changes proposed
by issue 442:

The cast-expression in a delete-expression shall
be evaluated exactly once. If the delete-expression calls the
implementation deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]), and if the value of the operand of the
delete expression is not a null pointer, the deallocation
function will deallocate the storage referenced by the pointer
thus rendering the pointer invalid. [Note: the value of a
pointer that refers to deallocated storage is
indeterminate. —end note]

Change 5.3.5 [expr.delete] paragraphs 6-7 as
follows:

TheIf the value of the operand of the
delete-expression is not a null pointer value, thedelete-expression will invoke the destructor (if any) for
the object or the elements of the array being deleted. In the
case of an array, the elements will be destroyed in order of
decreasing address (that is, in reverse order of the completion
of their constructor; see 12.6.2 [class.base.init]).

TheIf the value of the operand of the delete-expression is not a
null pointer value, thedelete-expression will call a
deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]). Otherwise, it is unspecified
whether the deallocation function will be called. [Note: The
deallocation function is called regardless of whether the
destructor for the object or some element of the array throws an
exception. —end note]

The value of the first argument supplied to one of thea
deallocation functions provided in the standard library may be a
null pointer value; if so, and if the deallocation function is
one supplied in the standard library, the call to the
deallocation function has no effect. Otherwise, the value
supplied to operator delete(void*) in the standard library shall
be one of the values returned by a previous invocation of either
operator new(std::size_t) or operator new(std::size_t, const
std::nothrow_t&) in the standard library, and the value supplied
to operator delete[](void*) in the standard library shall be one
of the values returned by a previous invocation of either
operator new[](std::size_t) or operator new[](std::size_t, const
std::nothrow_t&) in the standard library.

In the code above, class S does have a non-trivial constructor, the
default constructor generated by the compiler. According the text
above, the lifetime of the auto s would never begin because a
constructor for S is never called. I think the second case in the
text needs to include aggregate initialization.

Mike Miller:
I see a couple of ways of fixing the problem. One way would be
to change "the constructor call has completed" to "the object's
initialization is complete."

Another would be to add following "a class type with a non-trivial
constructor" the phrase "that is not initialized with the brace
notation (8.5.1 [dcl.init.aggr]
)."

The first formulation treats aggregate initialization like a
constructor call; even POD-type members of an aggregate could
not be accessed before the aggregate initialization completed.
The second is less restrictive; the POD-type members of the
aggregate would be usable before the initialization, and the
members with non-trivial constructors (the only way an
aggregate can acquire a non-trivial constructor) would be
protected by recursive application of the lifetime rule.

Proposed resolution (04/01):

In 3.8 [basic.life] paragraph 1, change

If T is a class type with a non-trivial constructor
(12.1 [class.ctor]), the constructor call has
completed.

to

If T is a class type with a non-trivial constructor
(12.1 [class.ctor]), the initialization is complete.
[Note: the initialization can be performed by a
constructor call or, in the case of an aggregate with an
implicitly-declared non-trivial default constructor, an
aggregate initialization (8.5.1 [dcl.init.aggr]).]

The wording in 3.8 [basic.life] paragraph 6 allows an
lvalue designating an out-of-lifetime object to be used as the
operand of a static_cast only if the conversion is
ultimately to "char&" or "unsigned char&".
This description excludes the possibility of using a cv-qualified
version of these types for no apparent reason.

Notes on 04/01 meeting:

The wording should be changed to allow cv-qualified char
types.

Proposed resolution (04/01):

In 3.8 [basic.life] paragraph 6 change the third bullet:

the lvalue is used as the operand of a static_cast
(5.2.9 [expr.static.cast])
(except when the conversion is ultimately to char& or unsigned
char&), or

to read:

the lvalue is used as the operand of a static_cast
(5.2.9 [expr.static.cast])
except when the conversion is ultimately to cv char& or
cv unsigned char&, or

594.
Coordinating issues 119 and 404 with delegating constructors

In ISO/IEC 14882:2003, the second bullet of 3.8 [basic.life] paragraph 1 reads,

if T is a class type with a non-trivial constructor
(12.1 [class.ctor]), the constructor call has completed.

Issue 119 pointed out that
aggregate initialization can be used with some classes with a
non-trivial implicitly-declared default constructor, and that
in such cases there is no call to the object's constructor.
The resolution for that issue was to change the previously-cited
wording to read,

If T is a class type with a non-trivial constructor
(12.1 [class.ctor], the initialization is complete.

Later (but before the WP was revised with the wording from
the resolution of issue 119),
issue 404 changed the 2003 wording to
read,

If T is a class type and the constructor invoked to
create the object is non-trivial (12.1 [class.ctor]),
the constructor call has completed.

thus reversing the effect of issue 119,
whose whole purpose was to cover objects with non-trivial constructors
that are not invoked.

Through an editorial error, the post-Redmond draft (N1905)
still contained the original 2003 wording that should have been
replaced by the resolution of issue 119, in addition to the new wording from the
resolution:

if T is a class type and the constructor invoked to
create the object is non-trivial (12.1 [class.ctor]),
the constructor call has completed. the initialization is
complete.

Finally, during the application of the edits for delegating
constructors (N1986), this editing error was “fixed”
by retaining the original 2003 wording (which was needed for the
application of the change specified in N1986), so that the
current draft (N2009) reads,

if T is a class type and the constructor invoked to
create the object is non-trivial (12.1 [class.ctor]),
the principal constructor call 12.6.2 [class.base.init]) has
completed.

Because the completion of the call to the principal constructor
corresponds to the point at which the object is “fully
constructed” (15.2 [except.ctor] paragraph 2), i.e.,
its initialization is complete, I believe that the exact wording
of the issue 119 resolution would be
correct and should be restored verbatim.

Proposed resolution (June, 2008):

Change 3.8 [basic.life] paragraph 1 as follows:

The lifetime of an object is a runtime property of the
object. An object is said to have non-trivial initialization if it
is of a class or aggregate type and it or one of its members is
initialized by a constructor other than a trivial default
constructor. [Note: Initialization by a trivial copy
constructor is non-trivial initialization. —end note]
The lifetime of an object of type T begins when:

storage with the proper alignment and size for type
T is obtained, and

if T is a class type and the constructor invoked to
create the object is non-trivial (12.1 [class.ctor]), the
principal constructor call (12.6.2 [class.base.init]) has
completed. [Note: the initialization can be performed by a
constructor call or, in the case of an aggregate with an
implicitly-declared non-trivial default constructor, an aggregate
initialization 8.5.1 [dcl.init.aggr]. —end note]the object has non-trivial initialization, its initialization is
complete.

The lifetime of an object of type T ends when...

644.
Should a trivial class type be a literal type?

The original proposed wording for 3.9 [basic.types]
paragraph 11 required a constexpr constructor for a literal class
only “if the class has at least one user-declared
constructor.” This wording was dropped during the
review by CWG out of a desire to ensure that literal types not
have any uninitialized members. Thus, a class like

struct pixel {
int x, y;
};

is not a literal type. However, if an object of that type is
aggregate-initialized or value-initialized, there can be no
uninitialized members; the missing wording should be restored in
order to permit use of expressions like pixel().x as
constant expressions.

Proposed resolution (February, 2008):

Change 3.9 [basic.types] paragraph 10 as follows:

A type is a literal type if it is:

a scalar type; or

a class type (clause 9 [class]) with

a trivial copy constructor,

a trivial destructor,

a trivial default constructor or at least one constexpr
constructor other than the copy constructor,

no virtual base classes, and

all non-static data members and base classes of literal types; or

an array of literal type.

158.
Aliasing and qualification conversions

3.10 [basic.lval] paragraph 15 lists the types via which
an lvalue can be used to access the stored value of an object; using
an lvalue type that is not listed results in undefined behavior. It
is permitted to add cv-qualification to the actual type of the object
in this access, but only at the top level of the type ("a cv-qualified
version of the dynamic type of the object").

However, 4.4 [conv.qual] paragraph 4 permits a
"conversion [to] add cv-qualifiers at levels other than the first in
multi-level pointers." The combination of these two rules
allows creation of pointers that cannot be dereferenced without
causing undefined behavior. For instance:

int* jp;
const int * const * p1 = &jp;
*p1; // undefined behavior!

The reason that *p1 results in undefined behavior
is that the type of the lvalue is const int * const",
which is not "a cv-qualified version of" int*.

Since the conversion is permitted, we must give it defined
semantics, hence we need to fix the wording in 3.10 [basic.lval] to include all possible conversions of the type via
4.4 [conv.qual].

Proposed resolution (04/01):

Add a new bullet to 3.10 [basic.lval] paragraph 15,
following "a cv-qualified version of the dynamic type of the
object:"

A type similar (as defined in 4.4 [conv.qual]) to
the dynamic type of the object,

649.
Optionally ill-formed extended alignment requests

The requirements on an implementation when presented with an
alignment-specifier not supported by that implementation in
that context are contradictory: 3.11 [basic.align] paragraph 9
says,

If a request for a specific extended alignment in a specific context
is not supported by an implementation, the implementation may reject
the request as ill-formed. The implementation may also silently ignore
the requested alignment.

In contrast, 7.6.2 [dcl.align] paragraph 2, bullet 4
says simply,

if the constant expression evaluates to an extended alignment and
the implementation does not support that alignment in the context of
the declaration, the program is ill-formed

with no provision to “silently ignore” the requested
alignment. These two passages need to be reconciled.

If the outcome of the reconciliation is to grant implementations
the license to accept and ignore extended alignment requests, the
specification should be framed in terms of mechanisms that already
exist in the Standard, such as undefined behavior and/or
conditionally-supported constructs; “ill-formed” is a
category that is defined by the Standard, not something that an
implementation can decide.

Notes from the February, 2008 meeting:

The consensus was that such requests should be ill-formed and
require a diagnostic. However, it was also observed that an
implementation need not reject an ill-formed program; the only
requirement is that it issue a diagnostic. It would thus be
permissible for an implementation to “noisily ignore”
(as opposed to “silently ignoring”) an unsupported
alignment request.

Proposed resolution (June, 2008):

Change 3.11 [basic.align] paragraph 9 as follows:

If a request for a specific extended alignment in a specific context
is not supported by an implementation, the implementation may
reject the request asprogram is ill-formed. The
implementation may also silently ignore the requested
alignment. [Note: aAdditionally, a request for runtime
allocation of dynamic memorystorage for which the
requested alignment cannot be honored mayshall be
treated as an allocation failure. —end note]

The null pointer value is converted to the null pointer value of the
destination type.

Add the following sentence to 5.2.9 [expr.static.cast]
paragraph 10:

The null pointer value (4.10 [conv.ptr]) is converted
to the null pointer value of the destination type.

Proposed resolution (October, 2005):

Add the indicated words to 4.10 [conv.ptr]
paragraph 2:

An rvalue of type “pointer to cvT,” where
T is an object type, can be converted to an rvalue of type “pointer to
cvvoid”. The result of converting a “pointer to
cvT” to a “pointer
to cvvoid” points to the start of the storage
location where the object of type T resides, as if the object
is a most derived object (1.8 [intro.object]) of
type T (that is, not a base class subobject). The null
pointer value is converted to the null pointer value of the
destination type.

Add the indicated words to 5.2.9 [expr.static.cast]
paragraph 11:

An rvalue of type “pointer to cv1void”
can be converted to an rvalue of type “pointer
to cv2T,” where T is an object type
and cv2 is the same cv-qualification as, or greater
cv-qualification than, cv1. The null pointer value is
converted to the null pointer value of the destination type. A
value of type pointer to object converted to “pointer
to cvvoid” and back, possibly with different
cv-qualification, shall have its original value...

654.
Conversions to and from nullptr_t

In the interest of promoting use of nullptr instead of the
integer literal 0 as the null pointer constant, the proposal accepted
by the Committee does not provide for converting a zero-valued integral
constant to type std::nullptr_t. However, this omission reduces
the utility of the feature for use in the library for smart pointers.
In particular, the addition of that conversion (along with a converting
constructor accepting a std::nullptr_t) would allow smart
pointers to be used just like ordinary pointers in expressions like:

The existing use of the “unspecified bool type” idiom
supports this usage, but being able to use std::nullptr_t
instead would be simpler and more elegant.

Jason Merrill: I have another reason to support the
conversion as well: it seems to me very odd for nullptr_t to
be more restrictive than void*. Anything we can do with an
arbitrary pointer, we ought to be able to do with nullptr_t
as well. Specifically, since there is a standard conversion from
literal 0 to void*, and there is a standard conversion
from void* to bool, nullptr_t should
support the same conversions.

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

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:

...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...

Change 5.2.9 [expr.static.cast] paragraph 2 as indicated:

...and B is notneither a virtual base class
of Dnor a base class of a virtual base class
of D...

Change 5.2.9 [expr.static.cast] paragraph 9 as indicated:

...and B is notneither a virtual base class
of Dnor a base class of a virtual base class of
D...

222.
Sequence points and lvalue-returning operators

I believe that the committee has neglected to take into
account one of the differences between C and C++ when defining
sequence points. As an example, consider

(a += b) += c;

where a, b, and c all have type
int. I believe that this expression has undefined behavior,
even though it is well-formed. It is not well-formed in C, because +=
returns an rvalue there. The reason for the undefined behavior is
that it modifies the value of `a' twice between sequence
points.

Expressions such as this one are sometimes genuinely useful.
Of course, we could write this particular example as

All of the potential rewrites involve multiply-evaluating
p[i] or unobvious circumlocations like creating references
to the array element.

One way to deal with this issue would be to include built-in operators
in the rule that puts a sequence point between evaluating a function's
arguments and evaluating the function itself. However, that might
be overkill: I see no reason to require that in

x[i++] = y;

the contents of `i' must be incremented before the
assignment.

A less stringent alternative might be to say that when a built-in
operator yields an lvalue, the implementation shall not subsequently
change the value of that object as a consequence of that operator.

I find it hard to imagine an implementation that does not do this
already. Am I wrong? Is there any implementation out there that
does not `do the right thing' already for (a += b) += c?

5.17 [expr.ass] paragraph 1 says,

The result of the assignment operation is the value stored in the left
operand after the assignment has taken place; the result is an lvalue.

What is the normative effect of the words "after the assignment has
taken place"? I think that phrase ought to mean that in addition to
whatever constraints the rules about sequence points might impose on
the implementation, assignment operators on built-in types have the
additional constraint that they must store the left-hand side's new
value before returning a reference to that object as their result.

One could argue that as the C++ standard currently stands, the
effect of x = y = 0; is undefined. The reason is that it
both fetches and stores the value of y, and does not fetch
the value of y in order to compute its new value.

I'm suggesting that the phrase "after the assignment has taken
place" should be read as constraining the implementation to set
y to 0 before yielding the value of y as the result
of the subexpression y = 0.

Note that this suggestion is different from asking that there be a
sequence point after evaluation of an assignment. In particular, I am
not suggesting that an order constraint be imposed on any side effects
other than the assignment itself.

Francis Glassborow:

My understanding is
that for a single variable:

Multiple read accesses without a write are OK

A single read access followed by a single write (of a value
dependant on the read, so that the read MUST happen first) is OK

A write followed by an actual read is undefined behaviour

Multiple writes have undefined behaviour

It is the 3) that is often ignored because in practice the compiler
hardly ever codes for the read because it already has that value but
in complicated evaluations with a shortage of registers, that is not
always the case. Without getting too close to the hardware, I think we
both know that a read too close to a write can be problematical on
some hardware.

So, in x = y = 0;, the implementation must NOT fetch a
value from y, instead it has to "know" what that value will
be (easy because it has just computed that in order to know what it
must, at some time, store in y). From this I deduce that
computing the lvalue (to know where to store) and the rvalue to know
what is stored are two entirely independent actions that can occur in
any order commensurate with the overall requirements that both
operands for an operator be evaluated before the operator is.

Erwin Unruh:

C
distinguishes between the resulting value of an assignment and putting the
value in store. So in C a compiler might implement the statement
x=y=0;
either as x=0;y=0; or as y=0;x=0;
In C the statement (x += 5) += 7; is not allowed because the first += yields
an rvalue which is not allowed as left operand to +=.
So in C an assignment is not a sequence of write/read because the result is
not really "read".

In C++ we decided to make the result of assignment an lvalue. In
this case we do not have the option to specify the "value" of the
result. That is just the variable itself (or its address in a
different view). So in C++, strictly speaking, the statement
x=y=0; must be implemented as y=0;x=y; which makes a
big difference if y is declared volatile.

Furthermore, I think undefined behaviour should not be the result of a
single mentioning of a variable within an expression. So the statement
(x +=5) += 7; should NOT have undefined behaviour.

In my view the semantics could be:

if the result of an assignment is used as an rvalue, its value is that of
the variable after assignment. The actual store takes place before the next
sequence point, but may be before the value is used. This is consistent with
C usage.

if the result of an assignment is used as an lvalue to store another
value, then the new value will be stored in the variable before the next
sequence point. It is unspecified whether the first assigned value is stored
intermediately.

if the result of an assignment is used as an lvalue to take an address,
that address is given (it doesn't change). The actual store of the new value
takes place before the next sequence point.

Jerry Schwarz:

My recollection is different from Erwin's. I am confident that the
intention when we decided to make assignments lvalues was not to
change the semantics of evaluation of assignments. The semantics was
supposed to remain the same as C's.

Ervin seems to assume that because assignments are lvalues, an
assignment's value must be determined by a read of the location. But
that was definitely not our intention. As he notes this has a
significant impact on the semantics of assignment to a volatile
variable. If Erwin's interpretation were correct we would have no way
to write a volatile variable without also reading it.

Lawrence Crowl:

For x=y=0, lvalue semantics implies an lvalue to rvalue
conversion on the result of y=0, which in turn implies a
read. If y is volatile, lvalue semantics implies
both a read and a write on y.

The standard apparently doesn't state whether there is a value
dependence of the lvalue result on the completion of the assignment.
Such a statement in the standard would solve the non-volatile C
compatibility issue, and would be consistent with a user-implemented
operator=.

Another possible approach is to state that primitive assignment
operators have two results, an lvalue and a corresponding
"after-store" rvalue. The rvalue result would be used when an rvalue
is required, while the lvalue result would be used when an lvalue is
required. However, this semantics is unsupportable for user-defined
assignment operators, or at least inconsistent with all
implementations that I know of. I would not enjoy trying to write
such two-faced semantics.

Erwin Unruh:

The intent was for assignments to behave the
same as in C. Unfortunately the change of the result to lvalue did not keep
that. An "lvalue of type int" has no "int" value! So there is a difference
between intent and the standard's wording.

So we have one of several choices:

live with the incompatibility (and the problems it has for volatile
variables)

make the result of assignment an rvalue (only builtin-assignment, maybe
only for builtin types), which makes some presently valid programs
invalid

make a special rule for assignment to a volatile lvalue of builtin
type

I think the last one has the least impact on existing programs, but it is an
ugly solution.

Andrew Koenig:

Whatever we may have intended, I do not think that there is any clean
way of making

volatile int v;
int i;
i = v = 42;

have the same semantics in C++ as it does in C. Like it or not, the
subexpression v = 42 has the type ``reference to volatile int,''
so if this statement has any meaning at all, the meaning must be to store 42
in v and then fetch the value of v to assign it to i.

Indeed, if v is volatile, I cannot imagine a
conscientious programmer
writing a statement such as this one. Instead, I would expect to see

v = 42;
i = v;

if the intent is to store 42 in v and then fetch the (possibly
changed) value of v, or

v = 42;
i = 42;

if the intent is to store 42 in both v and i.

What I do want is to ensure that expressions such as ``i = v = 42''
have well-defined semantics, as well as expressions such as
(i = v) = 42 or, more realistically, (i += v) += 42 .

I wonder if the following resolution is sufficient:

Append to 5.17 [expr.ass] paragraph 1:

There is a sequence point between assigning the new value to
the left operand and yielding the result of the assignment
expression.

I believe that this proposal achieves my desired effect of not
constraining when j is incremented in x[j++] = y,
because I don't
think there is a constraint on the relative order of incrementing j
and executing the assignment. However, I do think it allows expressions
such as (i += v) += 42, although with different semantics from C if
v is volatile.

Notes on 10/01 meeting:

There was agreement that adding a sequence point is probably the
right solution.

Notes from the 4/02 meeting:

The working group reaffirmed the sequence-point solution, but
we will look for any counter-examples where efficiency would be harmed.

For drafting, we note that ++x is defined in 5.3.2 [expr.pre.incr] as equivalent to x+=1 and is therefore
affected by this change. x++ is not affected. Also, we
should update any list of all sequence points.

Notes from October 2004 meeting:

Discussion centered around whether a sequence point “between
assigning the new value to the left operand and yielding the result of
the expression” would require completion of all side effects of
the operand expressions before the value of the assignment expression
was used in another expression. The consensus opinion was that it
would, that this is the definition of a sequence point. Jason Merrill
pointed out that adding a sequence point after the assignment is
essentially the same as rewriting

b += a

as

b += a, b

Clark Nelson expressed a desire for something like a
“weak” sequence point that would force the assignment to
occur but that would leave the side effects of the operands
unconstrained. In support of this position, he cited the following
expression:

j = (i = j++)

With the proposed addition of a full sequence point after the
assignment to i, the net effect is no change to j.
However, both g++ and MSVC++ behave differently: if the previous value
of j is 5, the value of the expression is 5 but j
gets the value 6.

Clark Nelson will investigate alternative approaches and report
back to the working group.

351.
Sequence point error: unspecified or undefined?

Between the previous and next sequence point a scalar object shall
have its stored value modified at most once by the evaluation of an
expression. Furthermore, the prior value shall be accessed only to
determine the value to be stored. The requirements of this
paragraph shall be met for each allowable ordering of the
subexpressions of a full expression; otherwise the behavior is
undefined. Example:

i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented

--end example]

So which is it, unspecified or undefined?

Notes from October 2002 meeting:

We should find out what C99 says and do the same thing.

Proposed resolution (April 2003):

Change the example in clause 5 [expr], paragraph 4 from

[Example:

i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; //i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented

--- end example]

to (changing "unspecified" to "undefined" twice)

[Example:

i = v[i++]; // the behavior is undefined
i = 7, i++, i++; //i becomes 9
i = ++i + 1; // the behavior is undefined
i = i + 1; // the value of i is incremented

--- end example]

451.
Expressions with invalid results and ill-formedness

If during the evaluation
of an expression, the result is not mathematically defined or not in
the range of representable values for its type, the behavior is
undefined, unless such an expression is a constant expression (5.19),
in which case the program is ill-formed.

Well, we do know that except in some contexts (e.g. controlling
expression of a #if, array bounds), a compiler is not required to
evaluate constant-expressions in compile time, right?

Now, let us consider, the following simple snippet:

if (a && 1/0)
...

with a, to fix our attention, being *not* a constant expression. The
quote above seems to say that since 1/0 is a constant
(sub-)expression, the program is ill-formed. So, is it the intent that
such ill-formedness is diagnosable at run-time? Or is it the intent
that the above gives undefined behavior (if 1/0 is evaluated) and is
not ill-formed?

I think the intent is actually the latter, so I propose the following
rewording of the quoted section:

If an expression is evaluated but its result is not mathematically
defined or not in the range of representable values
for its type the behavior is undefined, unless such an expression
is a constant expression (5.19) that shall be evaluated during
program translation, in which case the program is ill-formed.

Rationale (March, 2004):

We feel the standard is clear enough. The quoted sentence
does begin "If during the evaluation of an expression, ..."
so the rest of the sentence does not apply to an expression
that is not evaluated.

Note (September, 2004):

Gennaro Prota feels that the CWG missed the point of his
original comment: unless a constant expression appears in a
context that requires a constant expression, an
implementation is permitted to defer its evaluation to runtime.
An evaluation that fails at runtime cannot affect the
well-formedness of the program; only expressions that are
evaluated at compile time can make a program ill-formed.

The status has been reset to “open” to allow
further discussion.

Proposed resolution (October, 2004):

Change paragraph 5 of 5 [expr] as
indicated:

If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable
values for its type, the behavior is undefined, unless such an
expression is a constant expressionappears where an
integral constant expression is required (5.19 [expr.const]), in which case the program is ill-formed.

122.
template-ids as unqualified-ids

A template-id shall be used as an unqualified-id only
as specified in
14.7.2 [temp.explicit]
,
14.7 [temp.spec]
, and
14.5.5 [temp.class.spec]
.

What uses of template-ids
as unqualified-ids is this supposed to prevent? And is the
list of referenced sections correct/complete? For instance,
what about 14.8.1 [temp.arg.explicit],
"Explicit template argument specification?"
Does its absence from the list in
5.1.1 [expr.prim.general] paragraph 11 mean that
"f<int>()" is ill-formed?

This is even more confusing when you recall that unqualified-ids
are contained in qualified-ids:

qualified-id:
::optnested-name-specifiertemplateoptunqualified-id

Is the wording intending to say "used as an unqualified-id
that is not part of a qualified-id?" Or something else?

Here, it is not clear whether the friend declaration denotes
A B::C() or A::B C(), yet the standard does not resolve this
ambiguity.

The ambiguity arises since both the simple-type-specifier
(7.1.6.2 [dcl.type.simple]
paragra 1) and an
init-declararator
(8 [dcl.decl]
paragraph 1)
contain an optional :: and an optional
nested-name-specifier
(5.1.1 [expr.prim.general]
paragraph 1).
Therefore, two different ways to analyse this code are
possible:

Since it is a friend declaration, the init-declarator may be
qualified, and start with a global scope.

Suggested Resolution: In the definition of
nested-name-specifier, add a
sentence saying that a :: token immediately following a
nested-name-specifier is always considered as part of the
nested-name-specifier. Under this interpretation, the example is
ill-formed, and should be corrected as either

friend A (::B::C)(); //or
friend A::B (::C)();

An alternate suggestion — changing
7.1 [dcl.spec]
to say that

The longest sequence of tokens that could possibly be a type
name is taken as the decl-specifier-seq of a declaration.

— is undesirable because it would make the example well-formed
rather than requiring the user to disambiguate the declaration
explicitly.

Proposed resolution (04/01):

(See below for problem with this, from 10/01 meeting.)

In 5.1.1 [expr.prim.general] paragraph 7,

Before the grammar for qualified-id, start a new
paragraph 7a with the text

A qualified-id is an id-expression that contains the
scope resolution operator ::.

Following the grammar fragment, insert the following:

The longest sequence of tokens that could form a qualified-id
constitutes a single qualified-id. [Example:

It was pointed out that the proposed resolution does not deal with
cases like X::Y where X is a type but not a class type.
The working group reaffirmed its decision that the disambiguation should
be syntactic only, i.e., it should depend only on whether or not the name is a
type.

Jason Merrill
:

At the Seattle meeting, I suggested that a solution might be to change the
class-or-namespace-name in the nested-name-specifier
rule to just be
"identifier"; there was some resistance to this idea. FWIW, I've tried
this in g++. I had to revise the idea so that only the second and
subsequent names were open to being any identifier, but that seems to work
just fine.

Or some equivalent but right-associative formulation, if people feel that's
important, but it seems irrelevant to me.

Clark Nelson
:

Personally, I prefer the left-associative rule. I think it makes it easier
to understand. I was thinking about this production a lot at the meeting,
considering also some issues related to 301.
My formulation was getting kind
of ugly, but with a left-associative rule, it gets a lot nicer.

Your proposal isn't complete, however, as it doesn't allow template
arguments without an explicit template keyword. You probably want to add an
alternative for:

nested-name-specifier type-or-namespace-name::

There is admittedly overlap between this alternative and

nested-name-specifier identifier::

but I think they're both necessary.

Notes from the 4/02 meeting:

The changes look good. Clark Nelson will merge the two proposals
to produce a single proposed resolution.

Proposed resolution (April 2003):

nested-name-specifier is currently defined in
5.1.1 [expr.prim.general] paragraph 7 as:

Issue 215
is addressed by using type-name instead of class-name in the first alternative.
Issue 125 (this issue)
is addressed by using identifier instead of anything more specific in the third alternative.
Using left association instead of right association helps eliminate the need for class-or-namespace-name (or type-or-namespace-name, as suggested for issue 215).

It should be noted that this formulation also rules out the possibility of A::template B::, i.e. using the template keyword without any template arguments.
I think this is according to the purpose of the template keyword, and that the former rule allowed such a construct only because of the difficulty of formulation of a right-associative rule that would disallow it.
But I wanted to be sure to point out this implication.

113.
Visibility of called function

If no declaration of the called function is visible from the scope of
the call the program is ill-formed.

I think nothing there or in the previous paragraph indicates that
this does not apply to calls through pointer or virtual calls.

Mike Miller:
"The called function" is unfortunate phraseology; it makes it
sound as if it's referring to the function actually called, as
opposed to the identifier in the postfix expression. It's
wrong with respect to Koenig lookup, too (the declaration need
not be visible if it can be found in a class or namespace
associated with one or more of the arguments).

In fact, this paragraph should be a note. There's a general
rule that says you have to find an unambiguous declaration of
any name that is used
(3.4 [basic.lookup]
paragraph 1);
the only reason this paragraph
is here is to contrast with C's implicit declaration of called
functions.

Proposed resolution:

Change section 5.2.2 [expr.call] paragraph 2 from:

If no declaration of the called function is visible from the
scope of the call the program is ill-formed.

to:

[Note: if a function or member function name is used,
and name lookup (3.4 [basic.lookup]) does not find a
declaration of that name,
the program is ill-formed. No function is implicitly declared by such
a call. ]

118.
Calls via pointers to virtual member functions

Martin O'Riordan:
Having gone through all the relevant references in the IS, it is not
conclusive that a call via a pointer to a virtual member function
is polymorphic at all, and could legitimately be
interpreted as being static.

Consider 5.2.2 [expr.call]
paragraph 1:

The function called in a member function call is normally selected
according to the static type of the object expression (clause
10 [class.derived]
), but if that function is
virtual and is not specified using a qualified-id then
the function actually called will be the final overrider
(10.3 [class.virtual]
) of the selected
function in the dynamic type of the object expression.

Here it is quite specific that you get the polymorphic call only if you use
the unqualified syntax. But, the address of a member function is "always"
taken using the qualified syntax, which by inference would indicate that
call with a PMF is static and not polymorphic! Not what was intended.

Yet other references such as
5.5 [expr.mptr.oper]
paragraph 4:

If the dynamic type of the object does not contain the member to which
the pointer refers, the behavior is undefined.

indicate that the opposite may have been intended, by stating that it is the
dynamic type and not the static type that matters. Also,
5.5 [expr.mptr.oper]
paragraph 6:

If the result of .* or ->* is a function,
then that result can be used
only as the operand for the function
call operator (). [Example:

(ptr_to_obj->*ptr_to_mfct)(10);

calls the member function denoted by ptr_to_mfct
for the object pointed
to by ptr_to_obj. ]

which also implies that it is the object pointed to that determines both the
validity of the expression (the static type of 'ptr_to_obj'
may not have a
compatible function) and the implicit (polymorphic) meaning. Note too,
that this is stated in the non-normative example text.

Andy Sawyer:
Assuming the resolution is what I've assumed it is for the
last umpteen years (i.e. it does the polymorphic thing), then
the follow on to that is "Should there also be a way of selecting
the non-polymorphic behaviour"?

Mike Miller:
It might be argued that the current wording of
5.2.2 [expr.call]
paragraph 1 does give
polymorphic behavior to simple calls via pointers to members.
(There is no qualified-id in obj.*pmf, and the IS says
that if the function is not specified using a qualified-id, the
final overrider will be called.) However, it clearly says the wrong
thing when the pointer-to-member itself is specified using a
qualified-id (obj.*X::pmf).

Bill Gibbons:
The phrase qualified-id in
5.2.2 [expr.call]
paragraph 1 refers to the
id-expression and not to the "pointer-to-member expression"
earlier in the paragraph:

For a member function call, the postfix expression shall be an
implicit (9.3.1 [class.mfct.non-static]
,
9.4 [class.static]
) or explicit class member
access (5.2.5 [expr.ref]
) whose
id-expression is a function member name, or a pointer-to-member
expression (5.5 [expr.mptr.oper]
) selecting
a function member.

This was moved back to open for lack of a champion. Martin O'Riordan
is not expected to be attending meetings.

Proposed resolution (February, 2008):

Change 5.2.2 [expr.call] paragraph 1 as follows:

... For a member function call, the postfix expression shall be an
implicit (9.3.1 [class.mfct.non-static], 9.4 [class.static]) or
explicit class member access (5.2.5 [expr.ref]) whose
id-expression is a function member name, or a pointer-to-member
expression (5.5 [expr.mptr.oper]) selecting a function member.
The first expression in the postfix expression is then called the
object expression, and; the call is as a member of
the object pointed to or referred to by the object expression
(5.2.5 [expr.ref], 5.5 [expr.mptr.oper]). In the
case of an implicit class member access, the implied object is the one
pointed to by this. [Note: a member function call of
the form f() is interpreted as (*this).f() (see
9.3.1 [class.mfct.non-static]). —end note] If a function or
member function name is used, the name can be overloaded (clause
13 [over]), in which case the appropriate function shall
be selected according to the rules in 13.3 [over.match]. The function called in a member function call is
normally selected according to the static type of the object
expression (clause 10 [class.derived]), but if that function
is virtual and is not specified using a qualified-id
then the function actually called will be the final overrider
(10.3 [class.virtual]) of the selected function in the dynamic
type of the object expressionIf the selected function is
non-virtual, or if the id-expression in the class member access
expression is a qualified-id, that function is called.
Otherwise, its final overrider (10.3 [class.virtual]) in the
dynamic type of the object expression is called. ...

Change 5.5 [expr.mptr.oper] paragraph 4 as follows:

The first operand is called the object expression. If
the dynamic type of the object expression does not contain the
member to which the pointer refers, the behavior is undefined.

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.10 [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.

Issue 506 changed passing a non-POD
class type to an ellipsis from undefined behavior to
conditionally-supported behavior. As a result, an implementation could
conceivably reject code like the following:

This technique has become popular in template metaprogramming,
and no non-POD object is actually passed at runtime. Concepts
will eliminate much (perhaps not all) of the need for this
kind of programming, but legacy code will persist.

Perhaps this technique should be officially supported by allowing
implementations to reject passing a non-POD type to ellipsis only if
it appears in a potentially-evaluated expression?

Notes from the July, 2007 meeting:

The CWG agreed with the suggestion to allow such calls in
unevaluated contexts.

466.
cv-qualifiers on pseudo-destructor type

The type designated by the pseudo-destructor-name shall be the same
as the object type.

and also:

The cv-unqualified versions of the object type and of the type
designated by the pseudo-destructor-name shall be the same type.

Which is it? "The same" or "the same up to cv-qualifiers"? The
second sentence is more generous than the first. Most compilers seem
to implement the less restrictive form, so I guess that's what I think
we should do.

The left-hand side of the dot operator shall be of scalar type. The
left-hand side of the arrow operator shall be of pointer to scalar
type. This scalar type is the object type. The type designated by the
pseudo-destructor-name shall be the same as the object
type.The cv-unqualified versions of
the object type and of the type designated by the
pseudo-destructor-name shall be the same type. Furthermore,
the two type-names in a pseudo-destructor-name of the
form

::opt nested-name-specifieropt type-name ::~ type-name

shall designate the same scalar type. The cv-unqualified versions of
the object type and of the type designated by the
pseudo-destructor-name shall be the same type.

492.
typeid constness inconsistent with example

There is an inconsistency between the normative text in
section 5.2.8 [expr.typeid] and
the example that follows.

Here is the relevant passage (starting with paragraph 4):

When typeid is applied to a type-id, the result
refers to a std::type_info object representing the type of the
type-id. If the type of the type-id is a reference
type, the result of the typeid expression refers to a
std::type_info object representing the referenced type.

The top-level cv-qualifiers of the lvalue expression or the
type-id that is the operand of typeid are always
ignored.

and the example:

typeid(D) == typeid(const D&); // yields true

The second paragraph above says the “type-id that is
the operand”. This would be const D&. In
this case, the const is not at the top-level (i.e.,
applied to the operand itself).

By a strict reading, the above should yield false.

My proposal is that the strict reading of the normative test is correct.
The example is wrong. Different compilers here give different
answers.

Proposed resolution (April, 2005):

Change the second sentence of 5.2.8 [expr.typeid]
paragraph 4 as follows:

If the type of the type-id is a reference to a possibly
cv-qualified type, the result of the typeid expression
refers to a std::type_info object representing the
cv-unqualified referenced type.

54.
Static_cast from private base to derived class

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.

Rationale (04/99): A static_cast from a private
base to a derived class is not allowed outside a member from the
derived class, because 4.10 [conv.ptr]
paragraph 3 implies that the conversion is not valid. (Classic style
casts work.)

Reopened September 2003:

Steve Adamczyk:
It makes some sense to disallow the inverse conversion that is
pointer-to-member of derived to pointer-to-member of private base.
There's less justification for the pointer-to-private-base to
pointer-to-derived case. EDG, g++ 3.2, and MSVC++ 7.1 allow
the pointer case and disallow the pointer-to-member case.
Sun disallows the pointer case as well.

There's a tricky case with old-style casts: because the
static_cast interpretation is tried first, you want a case
like the above to be considered a static_cast, but then issue
an error, not be rejected as not a static cast; if you did the
latter, you would then try the cast as a reinterpret_cast.

Ambiguity and casting to a virtual base should likewise be
errors after the static_cast interpretation is selected.

Notes from the October 2003 meeting:

There was lots of sentiment for making things symmetrical:
the pointer case should be the same as the pointer-to-member case.
g++ 3.3 now issues errors on both cases.

We decided an error should be issued on both cases.
The access part of the check should be done later; by some
definition of the word the static_cast is valid, and then
later an access error is issued.
This is similar to the way standard conversions work.

Proposed Resolution (October 2003):

Replace paragraph 5.2.9 [expr.static.cast]/6:

The inverse of any standard conversion sequence (clause
4 [conv]), other than the
lvalue-to-rvalue (4.1 [conv.lval]),
array-to-pointer (4.2 [conv.array]),
function-to-pointer (4.3 [conv.func]), and
boolean (4.12 [conv.bool]) conversions, can be performed
explicitly using static_cast.
The lvalue-to-rvalue (4.1 [conv.lval]),
array-to-pointer (4.2 [conv.array]), and
function-to-pointer (4.3 [conv.func])
conversions are applied to the operand.
Such a
static_cast
is subject to the restriction that the explicit conversion does not
cast away constness (5.2.11 [expr.const.cast]), and the following
additional rules for specific cases:

with two paragraphs:

The inverse of any standard conversion sequence (clause
4 [conv]), other than the
lvalue-to-rvalue (4.1 [conv.lval]),
array-to-pointer (4.2 [conv.array]),
function-to-pointer (4.3 [conv.func]), and
boolean (4.12 [conv.bool]) conversions, can be performed
explicitly using static_cast.
A program is ill-formed if it
uses static_cast to perform the inverse of an ill-formed
standard conversion sequence.[Example:

The lvalue-to-rvalue (4.1 [conv.lval]),
array-to-pointer (4.2 [conv.array]), and
function-to-pointer (4.3 [conv.func])
conversions are applied to the operand.
Such a
static_cast
is subject to the restriction that the explicit conversion does not
cast away constness (5.2.11 [expr.const.cast]), and the following
additional rules for specific cases:

In addition, modify the second sentence of
5.4 [expr.cast]/5. The first two
sentences of 5.4 [expr.cast]/5 presently read:

The conversions performed by

a const_cast (5.2.11),

a static_cast (5.2.9),

a static_cast followed by a const_cast,

a reinterpret_cast (5.2.10), or

a reinterpret_cast followed by a const_cast,

can be performed using the cast notation of explicit type conversion.
The same semantic restrictions and behaviors apply.

Change the second sentence to read:

The same semantic restrictions and behaviors apply, with the exception
that in performing a static_cast in the following situations
the conversion is valid even if the base class is inaccessible:

a pointer to an object of derived class type or an lvalue of
derived class type may be explicitly converted to a pointer or
reference to an unambiguous base class type, respectively;

a pointer to member of derived class type may be explicitly
converted to a pointer to member of an unambiguous non-virtual base
class type;

a pointer to an object of an unambiguous non-virtual
base class type, an lvalue of an unambiguous non-virtual base
class type, or a pointer to member of an unambiguous
non-virtual base class type may be explicitly converted to a pointer,
a reference, or a pointer to member of a derived class type,
respectively.

Remove paragraph 5.4 [expr.cast]/7, which presently reads:

In addition to
those conversions,
the following
static_cast
and
reinterpret_cast
operations
(optionally followed by a
const_cast
operation)
may be performed using the cast notation of explicit type conversion,
even if the base class type is not accessible:

a pointer to an object of derived class type or an lvalue of derived class
type may be explicitly converted
to a pointer or reference to an unambiguous base class type, respectively;

a pointer to member of derived class type may be explicitly converted
to a pointer to member of an unambiguous non-virtual base class type;

a pointer to an object of non-virtual base class type, an lvalue
of non-virtual base class type, or a pointer to member of non-virtual
base class type may be explicitly converted to a pointer, a reference,
or a pointer to member of a derived class type, respectively.

The rules for static_cast permit the conversion to
"const D&" in two ways:

D is derived from B, and b is an lvalue, so a cast to D& is OK.

const D& t = b is valid, using the constructor for D. [Ed. note:
actually, this should be parenthesized initialization.]

The first alternative is 5.2.9 [expr.static.cast]/5; the second is
5.2.9 [expr.static.cast]/2.

Presumably the first alternative is better -- it's the "simpler"
conversion. The standard does not seem to make that clear.

Steve Adamczyk:
I take the "Otherwise" at the beginning of
5.2.9 [expr.static.cast]/3 as meaning that
the paragraph 2 interpretation is used if available, which means in
your example above interpretation 2 would be used. However, that's
not what EDG's compiler does, and I agree that it's not the "simpler"
conversion.

Proposed Resolution (October 2003):

Move paragraph 5.2.9/5:

An lvalue of type
``cv1B'',
where
B
is a class type, can be cast to type ``reference to
cv2D'',
where
D
is a class derived (clause
10 [class.derived]) from
B,
if a valid standard conversion from ``pointer to
D''
to ``pointer to
B''
exists (4.10 [conv.ptr]),
cv2
is the same cv-qualification as, or greater cv-qualification than,
cv1,
and
B
is not a virtual base class of
D.
The result is an lvalue of type
``cv2D.''
If the lvalue of type
``cv1B''
is actually a sub-object of an object of type
D,
the lvalue refers to the enclosing object of type
D.
Otherwise, the result of the cast is undefined.
[Example:

Insert Otherwise, before the text of paragraph
5.2.9 [expr.static.cast]/2
(which will become 5.2.9 [expr.static.cast]/3
after the above insertion), so that it
reads:

Otherwise, an expression
e
can be explicitly converted to a type
T
using a
static_cast
of the form
static_cast<T>(e)
if the declaration
"T t(e);"
is well-formed, for some invented temporary variable
t
(8.5 [dcl.init]).
The effect of such an explicit conversion is the same as performing the
declaration and initialization and then using the temporary variable
as the result of the conversion.
The result is an lvalue if
T
is a reference type (8.3.2 [dcl.ref]), and an rvalue otherwise.
The expression
e
is used as an lvalue if and only if the initialization uses it as an lvalue.

439.
Guarantees on casting pointer back to cv-qualified version of original type

there should be no call to "abort". The last sentence of Paragraph
5.2.9 [expr.static.cast] paragraph 10 should be changed to read:

A value of type pointer to object converted to "pointer to
cvvoid" and back to the original pointer type
(or a variant of the original pointer type that differs only in the
cv-qualifiers applied to the object type) will have its
original value.
[Example:

Rationale: The wording "possibly with different
cv-qualification" was chosen over the suggested wording to
allow for changes in cv-qualification at different levels in a
multi-level pointer, rather than only at the object type level.

This is because values of scope enumeration types (intentionally)
cannot be implicitly converted to integral types (4.5 [conv.prom]
and 4.7 [conv.integral]) and 5.2.9 [expr.static.cast] was not
updated to permit #2, although #1 is covered by paragraph 8.

Proposed resolution (June, 2008):

Add the following as a new paragraph following 5.2.9 [expr.static.cast] paragraph 8:

A value of a scoped enumeration type (7.2 [dcl.enum]) can be
explicitly converted to an integral type. The value is unchanged if
the original value can be represented by the specified
type. Otherwise, the resulting value is unspecified.

195.
Converting between function and object pointers

It is currently not permitted to cast directly between a pointer to
function type and a pointer to object type. This conversion is not
listed in 5.2.9 [expr.static.cast]
and
5.2.10 [expr.reinterpret.cast]
and thus
requires a diagnostic to be issued. However, if a sufficiently long
integral type exists (as is the case in many implementations), it is
permitted to cast between pointer to function types and pointer to
object types using that integral type as an intermediary.

In C the cast results in undefined behavior and thus does not
require a diagnostic, and Unix C compilers generally do not issue
one. This fact is used in the definition of the standard Unix
function dlsym, which is declared to return void*
but in fact may return either a pointer to a function or a pointer to
an object. The fact that C++ compilers are required to issue a
diagnostic is viewed as a "competitive disadvantage" for the language.

Suggested resolution: Add wording to
5.2.10 [expr.reinterpret.cast]
allowing
conversions between pointer to function and pointer to object types,
if the implementation has an integral data type that can be used as an
intermediary.

Several points were raised in opposition to this suggestion:

Early C++ supported this conversion and it was deliberately
removed during the standardization process.

The existence of an appropriate integral type is irrelevant to
whether the conversion is "safe." The condition should be on whether
information is lost in the conversion or not.

There are numerous ways to address the problem at an
implementation level rather than changing the language. For example,
the compiler could recognize the specific case of dlsym and
omit the diagnostic, or the C++ binding to dlsym could be
changed (using templates, for instance) to circumvent the violation.

The conversion is, in fact, not supported by C; the dlsym
function is simply relying on non-mandated characteristics of C
implementations, and we would be going beyond the requirements of C
compatibility in requiring (some) implementations to support the
conversion.

This issue is in fact not a defect (omitted or self-contradictory
requirements) in the current Standard; the proposed change would
actually be an extension and should not be considered until the full
review of the IS.

dlsym appears not to be used very widely, and the
declaration in the header file is not problematic, only calls to it.
Since C code generally requires some porting to be valid C++ anyway,
this should be considered one of those items that requires porting.

Martin O'Riordan suggested an alternative approach:

Do not allow the conversions to be performed via old-style casts.

Allow reinterpret_cast to perform the conversions with
the C-style semantics (undefined behavior if not supported).

Allow dynamic_cast to perform the conversions with
well-defined behavior: the result would be a null pointer if the
implementation could not support the requested conversion.

The advantage of this approach is that it would permit writing
portable, well-defined programs involving such conversions. However,
it breaks the current degree of compatibility between old and new
casts, and it adds functionality to dynamic_cast which is not
obviously related to its current meaning.

Notes from 04/00 meeting:

Andrew Koenig suggested yet another approach: specify that "no
diagnostic is required" if the implementation supports the conversion.

Later note:

It was observed that conversion between function and data pointers
is listed as a "common extension" in C99.

Notes on the 10/01 meeting:

It was decided that we want the conversion defined in such a way that
it always exists but is always undefined (as opposed to existing only
when the size relationship is appropriate, and being implementation-defined
in that case). This would allow an implementation to issue an error
at compile time if the conversion does not make sense.

Bill Gibbons notes that the definitions of the other similar casts are
inconsistent in this regard. Perhaps they should be updated as well.

Proposed resolution (April 2003):

After 5.2.10 [expr.reinterpret.cast]
paragraph 6, insert:

A pointer to a
function can be explicitly converted to a pointer to a function of a different
type. The effect of calling a function through a pointer to a function
type (8.3.5 [dcl.fct])
that is not the same as the type used in the definition of the function is
undefined. Except that converting an rvalue of type ``pointer to T1''
to the type ``pointer to T2'' (where T1 and T2 are
function types) and back to its original type yields the original pointer
value, the result of such a pointer conversion is unspecified. [Note: see
also 4.10 [conv.ptr] for more details of pointer conversions. ]
It is implementation defined whether a conversion from pointer to object to
pointer to function and/or a conversion from pointer to function to pointer to
object exist.

and in paragraph 10:

An lvalue expression of type T1 can be cast to the type
``reference to T2''
if T1 and T2 are object types and an expression of
type ``pointer to T1'' can be explicitly converted to the type
``pointer to T2'' using a reinterpret_cast. That is, a reference
cast reinterpret_cast< T& >(x) has the same effect
as the conversion *reinterpret_cast< T* >(&x) with
the built-in & and * operators.
The result is an lvalue that refers to the same object as the source lvalue,
but with a different type. No temporary is created, no copy is made, and
constructors (12.1 [class.ctor]) or conversion functions
(12.3 [class.conv]) are not called.

Drafting Note:

If either conversion exists, the implementation already has to define the
behavior (paragraph 3).

Notes from April 2003 meeting:

The new consensus is that if the implementation allows
this cast, pointer-to-function converted to pointer-to-object converted
back to the original pointer-to-function should work; anything else
is undefined behavior. If the implementation does not allow the cast,
it should be ill-formed.

Tom Plum is investigating a new concept, that of a
"conditionally-defined" feature, which may be applicable here.

Proposed Resolution (October, 2004):

(See paper J16/04-0067 = WG21 N1627 for background material and
rationale for this resolution. The resolution proposed here differs
only editorially from the one in the paper.)

Insert the following into 1.3 [intro.defs] and renumber
all following definitions accordingly:

1.3.2 conditionally-supported behavior

behavior evoked by a program construct that is not a mandatory
requirement of this International Standard. If a given implementation
supports the construct, the behavior shall be as described herein;
otherwise, the implementation shall document that the construct is not
supported and shall treat a program containing an occurrence of the
construct as ill-formed (1.3 [intro.defs]).

If a program contains a violation of any diagnosable
rule, or an occurrence of a construct described herein as
“conditionally-supported” or as resulting in
“conditionally-supported behavior” when the implementation
does not in fact support that construct, a conforming
implementation shall issue at least one diagnostic message, except
that

Insert the following as a new paragraph following 5.2.10 [expr.reinterpret.cast] paragraph 7:

Converting a pointer to a function to a pointer to an object type or
vice versa evokes conditionally-supported behavior. In any such
conversion supported by an implementation, converting from an rvalue
of one type to the other and back (possibly with different
cv-qualification) shall yield the original pointer value; mappings
between pointers to functions and pointers to objects are otherwise
implementation-defined.

Change 7.4 [dcl.asm] paragraph 1 as indicated:

The meaning of anAnasm declaration evokes
conditionally-supported behavior. If supported, its meaning is
implementation-defined.

Change 7.5 [dcl.link] paragraph 2 as indicated:

The string-literal indicates the required language linkage. The meaning of the
string-literal is implementation-defined. A linkage-specification with a string that
is unknown to the implementation is ill-formed.This International Standard
specifies the semantics of C and C++ language linkage. Other values of the
string-literal evoke conditionally-supported behavior, with
implementation-defined semantics. [Note: Therefore, a
linkage-specification with a string-literal that is
unknown to the implementation requires a diagnostic.When the
string-literal in a linkage-specification names a programming
language, the spelling of the programming language's name is
implementation-defined. [Note:It is recommended that the
spelling be taken from the document defining that language, for
example Ada (not ADA) and Fortran or
FORTRAN (depending on the vintage). The semantics of a
language linkage other than C++ or C are implementation-defined. ]

Change 14 [temp] paragraph 4 as indicated:

A template, a template explicit specialization (14.7.3 [temp.expl.spec]), or a class template partial specialization shall
not have C linkage. If the linkage of one of these is something other
than C or C++, the behavior is implementation-definedresult
is conditionally-supported behavior, with implementation-defined
semantics.

463.
reinterpret_cast<T*>(0)

Is reinterpret_cast<T*>(null_pointer_constant)
guaranteed to yield the
null pointer value of type T*?

I think a committee clarification is needed. Here's why:
5.2.10 [expr.reinterpret.cast]
par. 8 talks of "null pointer value", not
"null pointer constant", so it would seem that

reinterpret_cast<T*>(0)

is a normal int->T* conversion, with an implementation-defined result.

However a little note to
5.2.10 [expr.reinterpret.cast] par. 5 says:

Converting an integral constant expression (5.19) with value zero
always yields a null pointer (4.10), but converting other
expressions that happen to have value zero need not yield a null
pointer.

Where is this supported in normative text? It seems that either the
footnote or paragraph 8 doesn't reflect the intent.

SUGGESTED RESOLUTION: I think it would be better to drop the footnote
#64 (and thus the special case for ICEs), for two reasons:

a) it's not normative anyway; so I doubt anyone is relying on the
guarantee it hints at, unless that guarantee is given elsewhere in a
normative part

b) users expect reinterpret_casts to be almost always implementation
dependent, so this special case is a surprise. After all, if one wants
a null pointer there's static_cast. And if one wants reinterpret_cast
semantics the special case requires doing some explicit cheat, such as
using a non-const variable as intermediary:

It seems that not only that's providing a duplicate functionality, but
also at the cost to hide what seems the more natural one.

Notes from October 2004 meeting:

This footnote was added in 1996, after the invention of
reinterpret_cast, so the presumption must be that it was
intentional. At this time, however, the CWG feels that there is
no reason to require that reinterpret_cast<T*>(0)
produce a null pointer value as its result.

Converting an integral constant expression
(5.19 [expr.const]) with value zero always yields a null
pointer (4.10 [conv.ptr]), but converting other expressions
that happen to have value zero need not yield a null pointer.

Add the indicated note to 5.2.10 [expr.reinterpret.cast] paragraph
8:

The null pointer value (4.10 [conv.ptr]) is converted to
the null pointer value of the destination type. [Note:
A null pointer constant, which has integral type, is not necessarily
converted to a null pointer value. —end note]

If the second and third operands are lvalues and have
the same type, the result is of that type and is an lvalue
and it is a bit-field if the second or the third
operand is a bit-field, or if both are bit-fields.

In 5.17 [expr.ass] paragraph 1 (assignment operators)
add the indicated text (the original text is
as updated by issue 221, which is DR but not in TC1):

The assignment operator (=) and the compound assignment
operators all group right-to-left. All require a modifiable lvalue as
their left operand and return an lvalue with the type and value of
the left operand after the assignment has taken place. The result
in all cases is a bit-field if the left operand is a bit-field.

Note that issue 222 adds (non-conflicting) text at the end of
this same paragraph (5.17 [expr.ass] paragraph 1).

In 5.18 [expr.comma] paragraph 1 (comma operator), change:

The type and value of the result are the type and value of the right
operand; the result is an lvalue if its right operand is.

to

The type and value of the result are the type and value of the right
operand; the result is an lvalue if the right operand is an lvalue,
and is a bit-field if the right operand is an lvalue and a bit-field.

The size requested by an array allocation is computed by multiplying
the number of elements requested by the size of each element and adding
an implementation-specific amount for overhead. It is possible for this
calculation to overflow. Is an implementation required to detect this
situation and, for instance, throw std::bad_alloc?

On one hand, the maximum allocation size is one of the implementation
limits specifically mentioned in Annex B [implimits], and,
according to 1.4 [intro.compliance] paragraph 2, an implementation
is only required to "accept and correctly execute" programs that do
not violate its resource limits.

On the other hand, it is difficult or impossible for user code
to detect such overflows in a portable fashion, especially given that
the array allocation overhead is not fixed, and it would be a
service to the user to handle this situation gracefully.

Rationale (04/01):

Each implementation is required to document the maximum size
of an object (Annex B [implimits]). It is not
difficult for a program to check array allocations to ensure
that they are smaller than this quantity. Implementations
can provide a mechanism in which users concerned with this
problem can request extra checking before array allocations,
just as some implementations provide checking for array index
and pointer validity. However, it would not be appropriate to
require this overhead for every array allocation in every
program.

299.
Conversion on array bound expression in new

In 5.3.4 [expr.new], the standard says that the
expression in an array-new has to
have integral type. There's already a DR (issue 74)
that says it should also be allowed to have enumeration type. But, it should
probably also say that it can have a class type with a single
conversion to integral type; in other words the same thing as in
6.4.2 [stmt.switch] paragraph 2.

Suggested resolution:

In 5.3.4 [expr.new] paragraph 6, replace
"integral or enumeration type (3.9.1 [basic.fundamental])" with
"integral or enumeration type (3.9.1 [basic.fundamental]), or a class
type for which a single conversion function to
integral or enumeration type exists".

Proposed resolution (October, 2004):

Change 5.3.4 [expr.new] paragraph 6 as
follows:

Every constant-expression in a
direct-new-declarator shall be an integral constant
expression (5.19 [expr.const]) and evaluate to a
strictly positive value. The expression in a
direct-new-declarator shall havebe of
integral type, or enumeration type (3.9.1), or a
class type for which a single conversion function to integral or
enumeration type exists (12.3 [class.conv]). If the
expression is of class type, the expression is converted by
calling the conversion function, and the result of the conversion
is used in place of the original expression. The value of the
expression shall bewith a non-negative
value. [Example: ...

Proposed resolution (April, 2005):

Change 5.3.4 [expr.new] paragraph 6 as
follows:

Every constant-expression in a
direct-new-declarator shall be an integral constant
expression (5.19 [expr.const]) and evaluate to a
strictly positive value. The expression in a
direct-new-declarator shall have integral or enumeration
type (3.9.1 [basic.fundamental]) with a non-negative
valuebe of integral type, enumeration type, or a class type for
which a single conversion function to integral or enumeration type
exists (12.3 [class.conv]). If the expression is of class
type, the expression is converted by calling that conversion function,
and the result of the conversion is used in place of the original
expression. If the value of the expression is negative, the behavior
is undefined. [Example: ...

429.
Matching deallocation function chosen based on syntax or signature?

The fundamental issue here is whether the deletion-on-throw
is driven by the syntax of the new (placement or non-placement)
or by signature matching. If the former, the operator delete
would be called with the second argument equal to the size of
the class. If the latter, it would be called with the second
argument 0.

Core issue 127 (in TC1) dealt with
this topic. It removed some wording
in 15.2 [except.ctor] paragraph 2 that implied a
syntax-based interpretation, leaving wording
in 5.3.4 [expr.new] paragraph 19 that is
signature-based. But there is no accompanying
rationale to confirm an explicit choice of the signature-based
approach.

EDG and g++ get 0 for the second argument, matching the presumed
core issue 127 resolution. But maybe this should be revisited.

Notes from October 2003 meeting:

There was widespread agreement that the compiler shouldn't
just silently call the delete with either of the possible values.
In the end, we decided it's smarter to issue an error on this
case and force the programmer to say what he means.

Mike Miller's analysis of the status quo:
3.7.4.2 [basic.stc.dynamic.deallocation] paragraph 2
says that "operator delete(void*, std::size_t)" is a
"usual (non-placement) deallocation function" if the class does
not declare "operator delete(void*)."
3.7.4.1 [basic.stc.dynamic.allocation] does not use the
same terminology for allocation functions, but the most
reasonable way to understand the uses of the term "placement
allocation function" in the Standard is as an allocation function
that has more than one parameter and thus can (but need not) be
called using the "new-placement" syntax described in
5.3.4 [expr.new]. (In
considering issue 127,
the core group discussed and endorsed the
position that, "If a placement allocation function has default
arguments for all its parameters except the first, it can be
called using non-placement syntax.")

5.3.4 [expr.new] paragraph 19
says that any non-placement deallocation function
matches a non-placement allocation function, and that a placement
deallocation function matches a placement allocation function
with the same parameter types after the first -- i.e., a
non-placement deallocation function cannot match a placement
allocation function. This makes sense, because non-placement
("usual") deallocation functions expect to free memory obtained
from the system heap, which might not be the case for storage
resulting from calling a placement allocation function.

According to this analysis, the example shows a placement
allocation function and a non-placement deallocation function, so
the deallocation function should not be invoked at all, and the
memory will just leak.

Proposed Resolution (October 2003):

Add the following text at the end of 5.3.4 [expr.new]
paragraph 19:

If the lookup finds the two-parameter form of a usual deallocation function
(3.7.4.2 [basic.stc.dynamic.deallocation]), and that function, considered as
a placement deallocation function, would have been selected as a match
for the allocation function, the program is ill-formed.
[Example:

624.
Overflow in calculating size of allocation

[Voted into the WP at the September, 2008 meeting (resolution
in paper N2757).]

Issue 256 was closed without action,
principally on the the grounds that an implementation could provide a
means (command-line option, #pragma, etc.) for requesting
that the allocation size be checked for validity, but that “it
would not be appropriate to require this overhead for every array
allocation in every program.”

This rationale may be giving too much weight to the overhead such a
check would add, especially when compared to the likely cost of
actually doing the storage allocation. In particular, the test
essentially amounts to something like

(noting that max_allocation_size/sizeof(T) is a
compile-time constant). It might make more sense to turn the
rationale around and require the check, assuming that implementations
could provide a mechanism for suppressing it if needed.

Suggested resolution:

In 5.3.4 [expr.new] paragraph 7, add the following
words before the example:

If the value of the expression is such that the size of the allocated
object would exceed the implementation-defined limit, an exception of
type std::bad_alloc is thrown and no storage is obtained.

Note (March, 2008):

The Evolution Working Group has accepted the intent of
issue 256 and referred it to CWG for
action for C++0x (see paper J16/07-0033 = WG21 N2173).

Proposed resolution (March, 2008):

As suggested.

Notes from the June, 2008 meeting:

The CWG felt that this situation should not be treated like an
out-of-memory situation and thus an exception of type
std::bad_alloc (or, alternatively, returning a null pointer
for a throw() allocator) would not be appropriate.

Proposed resolution (June, 2008):

Change 5.3.4 [expr.new] paragraph 8 as follows:

If the value of the expression in a
direct-new-declarator is such that the size of the
allocated object would exceed the implementation-defined limit, no
storage is obtained and the new-expression terminates by
throwing an exception of a type that would match a handler
(15.3 [except.handle]) of type std::length_error
(19.2.4 [length.error]). Otherwise, ifWhen the value of thethatexpressionin a
direct-new-declarator is zero, the allocation function is
called to allocate an array with no elements.

[Drafting note: std::length_error is thrown by
std::string and std::vector and thus appears to
be the right choice for the exception to be thrown here.]

288.
Misuse of "static type" in describing pointers

The operand shall have a pointer type, or a class type having
a single conversion function to a pointer type.

However,
paragraph 3 of that same section says:

if the static type of the
operand is different from its dynamic type, the static type shall be a
base class of the operand's dynamic type and the static type shall
have a virtual destructor or the behavior is undefined.

Since the operand must be of pointer type, its static type is
necessarily the same as its dynamic type. That clause is clearly
referring to the object being pointed at, and not to the pointer operand
itself.

Correcting the wording gets a little complicated, because dynamic
and static types are attributes of expressions, not objects, and
there's no sub-expression of a delete-expression which has the
relevant types.

Suggested resolution:

then there is a static type and a dynamic type that the hypothetical
expression (*const-expression) would
have. If that static type is different from that dynamic type, then
that static type shall be a base class of that dynamic type, and that
static type shall have a virtual destructor, or the behavior is
undefined.

There's precedent for such use of hypothetical constructs: see
5.10 [expr.eq] paragraph 2, and 8.1 [dcl.name]
paragraph 1.

10.3 [class.virtual] paragraph 3 has a similar problem. It
refers to

the type of the pointer or reference denoting the object
(the static type).

The type of the pointer is different from the type of the
reference, both of which are different from the static type of
'*pointer', which is what I think was actually intended. Paragraph 6
contains the exact same wording, in need of the same correction. In
this case, perhaps replacing "pointer or reference" with "expression"
would be the best fix. In order for this fix to be sufficient,
pointer->member must be considered equivalent to
(*pointer).member, in which case the "expression" referred to
would be (*pointer).

12.5 [class.free] paragraph 4 says that

if a delete-expression is used to deallocate a class object
whose static type has...

This should be changed to

if a delete-expression is used to deallocate a class object
through a pointer expression whose dereferenced static type would
have...

The same problem occurs later,
when it says that the

static and dynamic types of the object shall be
identical

In this case you could replace "object" with "dereferenced
pointer expression".

Footnote 104 says that

5.3.5 [expr.delete] requires that ... the static type of the
delete-expression's operand be the same as its dynamic type.

This
would need to be changed to

the delete-expression's dereferenced
operand

Proposed resolution (December, 2006):

Change 5.3.5 [expr.delete] paragraph 3 as follows:

In the first alternative (delete object), if the static type of
the operandobject to be deleted is different from its
dynamic type, the static type shall be a base class of
the operand’s dynamic type of the object to be deleted
and the static type shall have a virtual destructor or the behavior is
undefined. In the second alternative (delete array) if the
dynamic type of the object to be deleted differs from its static type,
the behavior is undefined.

Change the footnote in 12.5 [class.free] paragraph 4 as
follows:

A similar provision is not needed for the array version
of operator delete because 5.3.5 [expr.delete]
requires that in this situation, the static type of the
delete-expression’s operandobject to be deleted
be the same as its dynamic type.

Change the footnote in 12.5 [class.free] paragraph 5 as
follows:

If the static type in the delete-expressionof the
object to be deleted is different from the dynamic type and the
destructor is not virtual the size might be incorrect, but that case
is already undefined; see 5.3.5 [expr.delete].

[Drafting notes: No change is required for
10.3 [class.virtual] paragraph 7 because “the type of
the pointer” includes the pointed-to type. No change is
required for 12.5 [class.free] paragraph 4 because
“...used to deallocate a class object whose static
type...” already refers to the object (and not the
operand expression).]

353.
Is deallocation routine called if destructor throws exception in delete?

In a couple of comp.std.c++ threads, people have asked
whether the Standard guarantees that the deallocation function
will be called in a delete-expression if the destructor throws
an exception. Most/all people have expressed the opinion that
the deallocation function must be called in this case, although
no one has been able to cite wording in the Standard supporting
that view.

The delete-expression will call a deallocation function
(3.7.4.2 [basic.stc.dynamic.deallocation])
[Note: The deallocation function is called regardless of
whether the destructor for the object or some element of the array
throws an exception. ]

442.
Incorrect use of null pointer constant in description of delete operator

After some discussion in comp.lang.c++.moderated we came to the conclusion
that there seems to be a defect in
5.3.5 [expr.delete]/4, which says:

The cast-expression in a delete-expression shall be evaluated exactly once.
If the delete-expression calls the implementation deallocation function
(3.7.3.2), and if the operand of the delete expression is not the null
pointer constant, the deallocation function will deallocate the storage
referenced by the pointer thus rendering the pointer invalid. [Note: the
value of a pointer that refers to deallocated storage is indeterminate. ]

In the second sentence, the term "null pointer constant" should be changed
to "null pointer". In its present form, the passage claims that the
deallocation function will deallocate the storage refered to by a null
pointer that did not come from a null pointer constant in the delete
expression. Besides, how can the null pointer constant be the operand of a
delete expression, as "delete 0" is an error because delete requires a
pointer type or a class type having a single conversion function to a
pointer type?

If the delete-expression calls the implementation deallocation
function (3.7.4.2 [basic.stc.dynamic.deallocation]), and if
the value of the operand of
the delete expression is not thea null
pointer constant, the deallocation function will deallocate the
storage referenced by the pointer thus rendering the pointer invalid.

Notes from October 2004 meeting:

This wording is superseded by, and this issue will be resolved
by, the resolution of issue 348.

659.
Alignment of function types

The specification for the alignof operator (5.3.6 [expr.alignof]) does not forbid function types as operands, although it
probably should.

Proposed resolution (March, 2008):

The issue, as described, is incorrect. The requirement in
5.3.6 [expr.alignof] is for “a complete object type,”
so a function type is already forbidden. However, the existing text
does have a problem in this requirement in that it does not allow a
reference type, as anticipated by paragraph 3. Consequently, the
proposal is to change 5.3.6 [expr.alignof] paragraph 1 as
indicated:

An alignof expression yields the alignment requirement of its operand
type. The operand shall be a type-id representing a complete object
type or a reference to a complete object type.

520.
Old-style casts between incomplete class types

The operand of a cast using the cast notation can be an rvalue of type
“pointer to incomplete class type”. The destination type
of a cast using the cast notation can be “pointer to incomplete
class type”. In such cases, even if there is a inheritance
relationship between the source and destination classes, whether the
static_cast or reinterpret_cast interpretation is
used is unspecified.

It's not entirely clear how a compiler can
choose static_cast as 5.4 [expr.cast] paragraph 6
seems to allow. I believe the intent of 5.4 [expr.cast]
paragraph 6 is to force the use of reinterpret_cast when
either are incomplete class types and static_cast iff the
compiler knows both types and there is a non-ambiguous
hierarchy-traversal between that cast (or maybe not, core issue 242 talks about this). I cannot see any
other interpretation because it isn't intuitive, every compiler I've
tried agrees with me, and neither standard pointer conversions
(4.10 [conv.ptr] paragraph 3) nor static_cast
(5.2.9 [expr.static.cast] paragraph 5) talk about incomplete
class types. If the committee agrees with me, I would like to see
4.10 [conv.ptr] paragraph 3 and 5.2.9 [expr.static.cast] paragraph 5 explicitly disallow incomplete class
types and the wording of 5.4 [expr.cast] paragraph 6
changed to not allow any other interpretation.

Proposed resolution (April, 2006):

Change 5.4 [expr.cast] paragraph 6 as indicated:

The operand of a cast using the cast notation can be an rvalue of type
“pointer to incomplete class type.” The destination type
of a cast using the cast notation can be “pointer to incomplete
class type.” In such cases, even if there is a inheritance
relationship between the source and destination classes, whether
the static_cast or reinterpret_cast interpretation
is used is unspecified.If both the operand and destination types
are class types and one or both are incomplete, it is unspecified
whether the static_cast or the reinterpret_cast
interpretation is used, even if there is an inheritance relationship
between the two classes. [Note: For example, if the classes
were defined later in the translation unit, a multi-pass compiler
would be permitted to interpret a cast between pointers to the classes
as if the class types were complete at that point. —end
note]

614.
Results of integer / and %

[Voted into the WP at the September, 2008 meeting as part of
paper N2757.]

The current Standard leaves it implementation-defined whether
integer division rounds the result toward 0 or toward negative
infinity and thus whether the result of % may be negative.
C99, apparently reflecting (nearly?) unanimous hardware practice, has
adopted the rule that integer division rounds toward 0, thus requiring
that the result of -1 % 5 be -1. Should the C++
Standard follow suit?

On a related note, does INT_MIN % -1 invoke undefined
behavior? The % operator is defined in terms of the
/ operator, and INT_MIN / -1 overflows, which by
5 [expr] paragraph 5 causes undefined behavior;
however, that is not the “result” of the %
operation, so it's not clear. The wording of 5.6 [expr.mul]
paragraph 4 appears to allow % to cause undefined behavior
only when the second operand is 0.

Proposed resolution (August, 2008):

Change 5.6 [expr.mul] paragraph 4 as follows:

The binary / operator yields the quotient, and the
binary % operator yields the remainder from the division
of the first expression by the second. If the second operand of
/ or % is zero the behavior is undefined;
otherwise (a/b)*b + a%b is equal to a. If both
operands are nonnegative then the remainder is nonnegative; if
not, the sign of the remainder is
implementation-defined. [Footnote: According to work
underway toward the revision of ISO C, the preferred algorithm
for integer division follows the rules defined in the ISO Fortran
standard, ISO/IEC 1539:1991, in which the quotient is always
rounded toward zero. —end footnote]. For
integral operands, the / operator yields the
algebraic quotient with any fractional part discarded;
[Footnote: This is often called “truncation towards
zero.” —end footnote] if the quotient
a/b is representable in the type of the result,
(a/b)*b + a%b is equal to a.

446.
Does an lvalue-to-rvalue conversion on the "?" operator produce a temporary?

The problem occurs when the value of the operator is determined to
be an rvalue, the selected argument is an lvalue, the type is a class
type and a non-const member is invoked on the modifiable rvalue result.

The types of the second and third operands are the same and
one is an rvalue. Nothing changes until p6 where an lvalue to
rvalue conversion is performed on the third operand.
12.2 [class.temporary] states that an lvalue to rvalue
conversion produces a temporary and there is nothing to remove
it. It seems clear that the assertion must pass, yet most
implementations fail.

There seems to be a defect in p3 b2 b1. First, the conditions to get
here and pass the test.

If E1 and E2 have class type, and the underlying class types are the
same or one is a base class of the other: E1 can be converted to
match E2 if the class of T2 is the same type as, or a base class of,
the class of T1, and the cv-qualification of T2 is the same
cv-qualification as, or a greater cv-qualification than, the
cv-qualification of T1.

If both E1 and E2 are lvalues, passing the conditions here also passes
the conditions for p3 b1. Thus, at least one is an rvalue. The case of
two rvalues is not interesting and the action is covered by the case
when E1 is an rvalue.

(0 ? D(13) : b1).inc();
assert(b1.v == 42);

E1 is changed to an rvalue of type T2 that still refers to the
original source class object (or the appropriate subobject thereof).
[Note: that is, no copy is made. ]

Having changed the rvalue to base type, we are back to the above case
where an lvalue to rvalue conversion is required on the third operand
at p6. Again, most implementations fail.

The remaining case, E1 an lvalue and E2 an rvalue, is the defect.

D d1(42);
(0 ? B(13) : d1).inc();
assert(d1.v == 42);

The above quote states that an lvalue of type T1 is changed to an rvalue
of type T2 without creating a temporary. This is in contradiction to
everything else in the standard about lvalue to rvalue conversions.
Most implementations pass in spite of the defect.

The usual accessible and unambiguous is missing from the base class.

There seems to be two possible solutions. Following other temporary
creations would produce a temporary rvalue of type T1 and change it
to an rvalue of type T2. Keeping the no copy aspect of this bullet
intact would change the lvalue of type T1 to an lvalue of type T2.
In this case the lvalue to rvalue conversion would happen in p6 as
usual.

Suggested wording for p3 b2 b1

The base part:

If E1 and E2 have class type, and the underlying class types are the
same or one is a base class of the other: E1 can be converted to match
E2 if the class of T2 is the same type as, or an accessible and
unambiguous base class of, the class of T1, and the cv-qualification
of T2 is the same cv-qualification as, or a greater cv-qualification
than, the cv-qualification of T1. If the conversion is applied:

The same type temporary version:

If E1 is an lvalue, an lvalue to rvalue conversion is applied. The
resulting or original rvalue is changed to an rvalue of type T2 that
refers to the same class object (or the appropriate subobject
thereof). [Note: that is, no copy is made in changing the type of
the rvalue. ]

The never copy version:

The lvalue(rvalue) E1 is changed to an lvalue(rvalue) of type T2
that refers to the original class object (or the appropriate
subobject thereof). [Note: that is, no copy is made. ]

The test case was posted to clc++m and results for implementations
were reported.

I see no defect with regards to lvalue to rvalue conversions; however,
there seems to be disagreement about what it means by implementers.
It may not be surprising because 5.16 and passing a POD struct to an
ellipsis are the only places where an lvalue to rvalue conversion
applies to a class type. Most lvalue to rvalue conversions are on
basic types as operands of builtin operators.

Notes from the March 2004 meeting:

We decided all "?" operators that return a class rvalue should
copy the second or third operand to a temporary. See
issue 86.

Proposed resolution (October 2004):

Change 5.16 [expr.cond] paragraph 3 bullet 2
sub-bullet 1 as follows:

if E1 and E2 have class type, and the
underlying class types are the same or one is a base class of the
other: E1 can be converted to match E2 if the
class of T2 is the same type as, or a base class of, the
class of T1, and the cv-qualification of T2 is
the same cv-qualification as, or a greater cv-qualification than,
the cv-qualification of T1. If the conversion is
applied, E1 is changed to an rvalue of type T2that still refers to the original source class object (or the
appropriate subobject thereof). [Note: that is, no copy is
made. —end note]by copy-initializing a
temporary of type T2 from E1 and using that
temporary as the converted operand.

Change 5.16 [expr.cond] paragraph 6 bullet 1 as
follows:

The second and third operands have the same type; the result is
of that type. If the operands have class type, the result is an
rvalue temporary of the result type, which is copy-initialized
from either the second operand or the third operand depending on
the value of the first operand.

Change 4.1 [conv.lval] paragraph 2 as follows:

The value contained in the object indicated by the lvalue is
the rvalue result. When an lvalue-to-rvalue conversion occurs
within the operand of sizeof (5.3.3 [expr.sizeof]) the value contained in the referenced object is
not accessed, since that operator does not evaluate its operand.
Otherwise, if the lvalue has a class type, the conversion
copy-initializes a temporary of type T from the lvalue
and the result of the conversion is an rvalue for the temporary.
Otherwise, the value contained in the object indicated by the
lvalue is the rvalue result.

5.19 [expr.const] paragraph 1 implies that some kinds of
nonconstant expressions are allowed inside a sizeof in
a constant expression, but it's not clear that this was intended
to extend all the way to things like overload resolution.
Allowing such things has some hidden
costs. For example, name mangling has to be able to represent all
operators, including calls, and not just the operators that can appear
in constant expressions.

If complex expressions are
indeed allowed, it should be because of an explicit
committee decision rather than because of some looseness in this
section of the standard.

Notes from the 4/02 meeting:

Any argument for restricting such expressions must involve a
cost/benefit ratio: a restriction would be palatable only if it
causes minimum hardship for users and allows a substantial
reduction in implementation cost. If we propose a restriction,
it must be one that library writers can live with.

Lots of these cases fail with current compilers, so there can't
be a lot of existing code using them. We plan to find out what
cases there are in libraries like Loki and Boost.

We noted that in many cases one can move the code into a class
to get the same result. The implementation problem comes up
when the expression-in-sizeof is in a template deduction
context or part of a template signature. The problem cases
are ones where an error causes deduction to fail, as opposed
to contexts where an error causes a diagnostic. The latter
contexts are easier to handle; however, there are situations
where "fail deduction" may be the desired behavior.

The core working group liked the idea of a restriction that
says that expressions inside sizeof in template signature contexts
must be otherwise valid as nontype template argument expressions
(i.e., integer operations only, limited casts). This of
course is subject to whether users can live with that restriction.
This topic was brought up in full committee, but there was
limited feedback from other groups.

It was also noted that if typeof (whatever it is called)
is added, there may be a similar issue there.

as a valid declaration (if the proposal is accepted). If [the
restrictions in the April, 2003 note] really applied to decltype, the
declaration above would be invalid. AFAICT every non-trivial use of
decltype in a template function declaration would be invalid. And for
me this would render my favorite proposal useless.

Jaakko Jarvi: Just reinforcing that this is important and
hope for insights. The topic is discussed a bit on page 10 of the
latest revision of the proposal (N1705). Here's a quote from the
proposal:

However, it is crucial that no restrictions are placed on what kinds
of expressions are allowed inside decltype, and
therefore also inside sizeof. We suggest that issue 339
is resolved to require the compiler to fail deduction (apply the
SFINAE principle), and not produce an error, for as large set of
invalid expressions in operands of sizeof or
decltype as is possible to comfortably implement. We wish
that implementors aid in classifying the kinds of expressions that
should produce errors, and the kinds that should lead to failure of
deduction.

Notes from the April, 2007 meeting:

The CWG is pursuing a compromise proposal, to which the EWG has
tentatively agreed, which would allow arbitrary expressions in the
return types of function templates but which would restrict the
expressions that participate in the function signature (and thus in
overload resolution) to those that can be used as non-type
template arguments. During deduction and overload resolution,
these complex return types would be ignored; that is, there would
be no substitution of the deduced template arguments into the return
type at this point. If such a function were selected by overload
resolution, however, a substitution failure in the return type would
produce a diagnostic rather than a deduction failure.

This approach works when doing overload resolution in the context
of a function call, but additional tricks (still being defined) are
needed in other contexts such as friend function declaration matching
and taking the address of a function, in which the return type does
play a part.

Notes from the July, 2007 meeting:

The problem is whether arbitrary expressions (for example,
ones that include overload resolution) are allowed in template
deduction contexts, and, if so, which expression errors are
SFINAE failures and which are hard errors.

This issue deals with arbitrary expressions inside sizeof in
deduction contexts. That's a fringe case right now (most
compilers don't accept them). decltype makes the problem worse,
because the standard use case is one that involves overload
resolution. Generalized constant expressions make it worse yet,
because they allow overload resolution and class types to show up
in any constant expression in a deduction context.

Why is this an issue? Why don't we just say everything is
allowed and be done with it?

Because it's hard to implement the general case. Template
deduction/substitution has historically used a simplified model
of semantic checking, i.e., the SFINAE rules (which are mostly
about types), instead of full semantic checking. This limited
semantic checking is typically done by completely separate code
from the code for “normal” expression checking, and
it's not easy to extend it to the general
case. “Speculative compilation” sounds like an easy
way out, but in practice compilers can't do that.

Because it affects name mangling and therefore the ABI.

Because we need to figure out what to say and how to say it
in the Standard.

At the April, 2007 meeting, we were headed toward a solution
that imposed a restriction on expressions in deduction contexts,
but such a restriction seems to really hamper uses of constexpr
functions. So we're now proposing that fully general expressions
be allowed, and that most errors in such expressions be treated
as SFINAE failures rather than errors.

One issue with writing Standard wording for that is how to
define “most.” There's a continuum of errors, some
errors being clearly SFINAE failures, and some clearly
“real” errors, with lots of unclear cases in
between. We decided it's easier to write the definition by
listing the errors that are not treated as SFINAE failures, and
the list we came up with is as follows:

errors that occur while processing some entity external to
the expression, e.g., an instantiation of a template or the
generation of the definition of an implicitly-declared copy
constructor

errors due to implementation limits

errors due to access violations (this is a judgment call,
but the philosophy of access has always been that it doesn't
affect visibility)

Everything else produces a SFINAE failure rather than a hard
error.

There was broad consensus that this felt like a good solution,
but that feeling was mixed with trepidation on several
fronts:

The implementation cost is quite significant, at least for
EDG and Microsoft (under GCC, it may be easier). It involves
moving around a large amount of code. This may delay
implementation and introduce bugs in compilers.

While it seems upward compatible with C++03, it's possible it
will break existing code. Any big change in template processing
has a pretty good chance of breaking something.

Since there is no implementation, we don't really know how it
will work in the real world.

We will be producing wording for the Working Draft for the
October, 2007 meeting.

366.
String literal allowed in integral constant expression?

is well-formed, since it is an integral constant expression.
Since that may not be obvious, here is why:

5.19 [expr.const] paragraph 1 says that an integral constant
expression may involve literals (2.14 [lex.literal]);
"Hello, world" is a literal. It restricts
operators to not use certain type conversions; this expression does
not use type conversions. It further disallows functions, class
objects, pointers, ... - this expression is none of those, since it
is an array.

However, 16.1 [cpp.cond] paragraph 6 does not explain what
to do with this if-group, since
the expression evaluates neither to false(zero) nor true(non-zero).

Proposed resolution (October 2002):

Change the beginning of the second sentence of
5.19 [expr.const] paragraph 1 which currently reads

An integral constant-expression can involve only literals
(2.14 [lex.literal]), ...

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-callfunction call (including
new-expressions and delete-expressions), or comma
operators, or throw-expressions shall not be used.

The proposed resolution could potentially be read as saying that
the prohibited operations and operators would be permitted in integral
constant expressions that are non-type template-arguments. John
Spicer is investigating an alternate approach, to say that expressions
in non-type template arguments are not part of the expression in which
the template-id appears (in contrast to the operand of
sizeof, which is part of the containing expression).

Additional note (May, 2008):

This issue is resolved by the rewrite of 5.19 [expr.const]
that was done in conjunction with the constexpr proposal, paper
N2235.

684.
Constant expressions involving the address of an automatic variable

Add the following bullet to the list in 5.19 [expr.const]
paragraph 2:

an id-expression that refers to a variable with
automatic storage duration unless a permitted lvalue-to-rvalue
conversion is applied (see above)

Proposed resolution (June, 2008):

Change 3.6.2 [basic.start.init] paragraph 1 as
follows:

Objects with static storage duration (3.7.1 [basic.stc.static]) or
thread storage duration (3.7.2) shall be zero-initialized
(8.5 [dcl.init]) before any other initialization takes
place. A reference with static or thread storage duration and an
object of trivial or literal type with static or thread storage
duration can be initialized with a constant expression (5.19 [expr.const]); this is called constant initialization.Constant initialization is performed:

if an object of trivial or literal type with static or
thread storage duration is initialized with a constant expression
(5.19 [expr.const]), or

if a reference with static or thread storage duration is
initialized with a constant expression that is not an lvalue
designating an object with thread or automatic storage
duration.

Together, zero-initialization and constant
initialization...

Add the following in 5.19 [expr.const] paragraph
2:

an lvalue-to-rvalue conversion (4.1) unless it is applied
to...

an array-to-pointer conversion (4.2 [conv.array]) that
is applied to an lvalue that designates an object with thread or
automatic storage duration

a unary operator & (5.3.1 [expr.unary.op])
that is applied to an lvalue that designates an object with thread or
automatic storage duration

an id-expression that refers to a variable or data
member of reference type;

...

(Note: the change to 3.6.2 [basic.start.init] paragraph 1
needs to be reconciled with the conflicting change in
issue 688.)

276.
Order of destruction of parameters and temporaries

On exit from a scope (however accomplished), destructors (12.4 [class.dtor]) are called for all constructed objects with automatic
storage duration (3.7.3 [basic.stc.auto]) (named objects or
temporaries) that are declared in that scope, in the reverse order of
their declaration.

This wording is problematic for temporaries and for parameters.
First, temporaries are not "declared," so this requirement does not
apply to them, in spite of the assertion in the quoted text that it
does.

Second, although the parameters of a function are declared
in the called function, they are constructed and destroyed in the
calling context, and the order of evaluation of the arguments is
unspecified (cf 5.2.2 [expr.call] paragraphs 4 and 8).
The order of destruction of the parameters might, therefore, be
different from the reverse order of their declaration.

Notes from 04/01 meeting:

Any resolution of this issue should be careful not to introduce
requirements that are redundant or in conflict with those of other
parts of the IS. This is especially true in light of the pending
issues with respect to the destruction of temporaries (see issues
86, 124,
199, and 201).
If possible, the wording of a resolution should simply reference
the relevant sections.

It was also noted that the temporary for a return value is
also destroyed "out of order."

Note that issue 378 picks a nit
with the wording of this same paragraph.

Proposed Resolution (November, 2006):

Change 6.6 [stmt.jump] paragraph 2 as follows:

On exit from a scope (however accomplished), destructors
(12.4 [class.dtor]) are called for all constructed objects
with automatic storage duration (3.7.3 [basic.stc.auto]) (named
objects or temporaries) that are declared in that scope, in the
reverse order of their declaration.variables with automatic
storage duration (3.7.3 [basic.stc.auto]) that have been
constructed in that scope are destroyed in the reverse order of their
construction. [Note: For temporaries, see 12.2 [class.temporary].
—end note] Transfer out of a loop...

378.
Wording that says temporaries are declared

On exit from a scope (however accomplished), destructors
(12.4 [class.dtor])
are called for all constructed objects with automatic storage
duration (3.7.3 [basic.stc.auto])
(named objects or temporaries) that are declared
in that scope.

It refers to objects "that are declared" but the text in parenthesis
also mentions temporaries, which cannot be declared. I think that text
should be removed.

Bjarne Stroustrup:
... and [the ARM] disallows declaring a function inline after it
has been called.

This may still be a good resolution.

Steve Clamage:
But the situation in the ARM is the reverse: Declare a function
inline, and define it later (with no intervening call). That's
a long-standing rule in C++, and allows you to write member
function definitions outside the class.

In my example, the compiler could reasonably process the entire
function as out-of-line, and not discover the inline declaration
until it was too late to save the information necessary for inline
generation. The equivalent of another compiler pass would be needed
to handle this situation.

Bjarne Stroustrup:
I see, and I think your argument it conclusive.

Steve Clamage:
I'd like to open a core issue on this point, and I recommend wording
along the lines of: "A function defined without an inline specifier
shall not be followed by a declaration having an inline specifier."

I'd still like to allow the common idiom

class T {
int f();
};
inline int T::f() { ... }

Martin Sebor:
Since the inline keyword is just a hint to the compiler, I don't see
any harm in allowing the construct. Your hypothetical compiler can
simply ignore the inline on the second declaration. On the other hand,
I feel that adding another special rule will unnecessarily complicate
the language.

Steve Clamage:
The inline specifier is more than a hint. You can have multiple
definitions of inline functions, but only one definition of a
function not declared inline. In particular, suppose the above
example were in a header file, and included multiple times in
a program.

Proposed resolution (October, 2004):

Add the indicated words to 7.1.2 [dcl.fct.spec]
paragraph 4:

An inline function shall be defined in every translation unit in
which it is used and shall have exactly the same definition in
every case (3.2 [basic.def.odr]). [Note: a call to
the inline function may be encountered before its definition
appears in the translation unit. —end note] If the
definition of a function appears in a translation unit before its
first declaration as inline, the program is ill-formed. If a
function with external linkage is declared inline in one
translation unit...

396.
Misleading note regarding use of auto for disambiguation

BTW, I noticed that the following note in 7.1.1 [dcl.stc]
paragraph 2 doesn't seem to have
made it onto the issues list or into the TR:

[Note: hence, the auto specifier is almost always redundant and not
often used; one use of auto is to distinguish a declaration-statement
from an expression-statement (stmt.ambig) explicitly. --- end note]

I thought that this was well known to be incorrect, because using auto
does not disambiguate this. Writing:

auto int f();

is still a declaration of a function f, just now with an error since the
function's return type may not use an auto storage class specifier. I
suppose an error is an improvement over a silent ambiguity going the
wrong way, but it's still not a solution for the user who wants to
express the other in a compilable way.

Proposed resolution: Replace that note with the following note:

[Note: hence, the auto specifier is always redundant and not often
used. --- end note]

John Spicer:
I support the proposed change, but I think the disambiguation case is not the
one that you describe. An example of the supposed disambiguation is:

cfront would take "int(i)" as a cast of ::i, so the auto would force what it
would otherwise treat as a statement to be considered a declaration
(cfront 3.0 warned that this would change in the future).

In a conforming compiler the auto is always redundant (as you say) because
anything that could be considered a valid declaration should be treated as
one.

Proposed resolution (April 2003):

Replace 7.1.1 [dcl.stc] paragraph 2

[Note: hence, the auto specifier
is almost always redundant and not often used;
one use of auto is to distinguish
a declaration-statement from
an expression-statement (6.8 [stmt.ambig])
explicitly. --- end note]

with

[Note: hence, the auto specifier
is always redundant and not often used.
One use of auto is to distinguish
a declaration-statement from an expression-statement
explicitly
rather than relying on the disambiguation rules
(6.8 [stmt.ambig]),
which may aid readers.
--- end note]

397.
Same address for string literals from default arguments in inline functions?

Are string literals from default arguments
used in extern inlines supposed to have the same addresses across
all translation units?

void f(const char* = "s")
inline g() {
f();
}

Must the "s" strings be the same in all copies of the
inline function?

Steve Adamczyk:
The totality of the standard's wisdom on this topic is
(7.1.2 [dcl.fct.spec] paragraph 4):

A string literal in an extern inline function is the same object
in different translation units.

I'd hazard a guess that a literal in a default argument expression
is not "in" the extern inline function (it doesn't appear in the
tokens of the function), and therefore it need not be
the same in different translation units.

I don't know that users would expect such strings to have
the same address, and an equally valid (and incompatible) expectation
would be that the same string literal would be used for every expansion of
a given default argument in a single translation unit.

Notes from April 2003 meeting:

The core working group feels that the address of a string literal
should be guaranteed to be the same only if it actually appears
textually within the body of the inline function. So a string in
a default argument expression
in a block extern declaration inside the body of a function would
be the same in all instances of the function. On the other
hand, a string in a default argument expression in the header of
the function (i.e., outside of the body) would not be the same.

Proposed resolution (April 2003):

Change the last sentence and add the note to the end of
7.1.2 [dcl.fct.spec] paragraph 4:

A string literal in the body of an extern inline
function is the same
object in different translation units.
[Note: A string literal that is encountered only in the context of a
function call (in the default argument expression of the called function),
is not “in” the extern inline function.]

Notes from October 2003 meeting:

We discussed ctor-initializer lists and decided that they are
also part of the body. We've asked Clark Nelson to work on
syntax changes to give us a syntax term for the body of a
function so we can refer to it here. See also
issue 452, which could use this term.

(October, 2005: moved to “review” status in concert with
issue 452. With that resolution, the wording
above needs no further changes.)

Proposed resolution (April, 2006):

Change the last sentence and add the note to the end of
7.1.2 [dcl.fct.spec] paragraph 4:

A string literal in the body of an extern inline
function is the same object in different translation units.
[Note: A string literal appearing in a default argument
expression is not considered to be “in the body”
of an inline function merely by virtue of the expression’s use in a
function call from that inline function. —end note]

477.
Can virtual appear in a friend declaration?

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 declarationsthe initial declaration
of a non-static class member functions that appear within a
member-specification of a class definitionfunction;
see 10.3 [class.virtual].

The explicit specifier shall be used only
in declarationsthe declaration of constructorsa constructor within aits class definition; see
12.3.1 [class.conv.ctor].

647.
Non-constexpr instances of constexpr constructor templates

If the instantiated template specialization of a constexpr function
template would fail to satisfy the requirements for a constexpr
function, the constexpr specifier is ignored and the
specialization is not a constexpr function.

One would expect to see a similar provision for an instantiated
constructor template (because the requirements for a constexpr function
[paragraph 3] are different from the requirements for a constexpr
constructor [paragraph 4]), but there is none; constexpr constructor
templates are not mentioned.

Suggested resolution:

Change the wording of 7.1.5 [dcl.constexpr] paragraph 5 as
indicated:

If the instantiated template specialization of a constexpr function
template would fail to satisfy the requirements for a constexpr
function or constexpr constructor, as appropriate to the function
template, the constexpr specifier is ignored and the
specialization is not a constexpr function or constexpr
constructor.

Proposed resolution (June, 2008):

[Drafting note: This resolution goes beyond the problem
described in the issue discussion, which is one aspect of the general
failure of the existing wording to deal consistently with the
distinctions between constexpr functions and constexpr
constructors. The wording below attempts to rectify that problem
systematically.]

Change 7.1.5 [dcl.constexpr] paragraph 2 as follows:

A constexpr specifier used in a function declarationthe declaration of a function that is not a constructor
declares that function to be a constexpr function. Similarly, a
constexpr specifier used in a constructor declaration
declares that constructor to be a constexpr
constructor. Constexpr functions and constexpr constructors are
implicitly inline (7.1.2 [dcl.fct.spec]). A constexpr
function shall not be virtual (10.3).

Change 7.1.5 [dcl.constexpr] paragraph 3 as follows:

The definition of a constexpr function shall satisfy the following
constraints:

it shall not be virtual (10.3 [class.virtual])

its return type shall be a literal type

each of its parameter types shall be a literal type

its function-body shall be a compound-statement of the form

{ returnexpression; }

where expression is a potential constant expression
(5.19 [expr.const])

every implicit conversion used in converting expression
to the function return type (8.5 [dcl.init]) shall be one of
those allowed in a constant expression (5.19 [expr.const]).

[Example:...

Change 7.1.5 [dcl.constexpr] paragraph 4 as follows:

The definition of a constexpr constructor shall satisfy the
following constraints:

each of its parameter types shall be a literal
type

its function-body shall not be a
function-try-block

the compound-statement of its function-body shall
be empty

every non-static data member and base class sub-object shall be
initialized (12.6.2 [class.base.init])

every constructor involved in initializing non-static data
members and base class sub-objects invoked by a
mem-initializer shall be a constexpr constructor invoked
with potential constant expression arguments, if any.

every constructor argument and full-expression in a
mem-initializer shall be a potential constant
expression

every implicit conversion used in converting a constructor
argument to the corresponding parameter type and converting a
full-expression to the corresponding member type shall be one of those
allowed in a constant expression.

A trivial copy constructor is also a constexpr
constructor. [Example: ...

Change 7.1.5 [dcl.constexpr] paragraph 5 as follows:

If the instantiated template specialization of a constexpr function
template would fail to satisfy the requirements for a constexpr
function or constexpr constructor, the constexpr
specifier is ignored and the specialization is not a constexpr
function.

Change 7.1.5 [dcl.constexpr] paragraph 6 as follows:

A constexpr specifier used infor a non-static
member function definitionthat is not a constructor
declares that member function to be const (9.3.1 [class.mfct.non-static]). [Note: ...

648.
Constant expressions in constexpr initializers

The current wording of 7.1.5 [dcl.constexpr] paragraph 7
seems not quite correct. It reads,

A constexpr specifier used in an object declaration declares
the object as const. Such an object shall be initialized, and
every expression that appears in its initializer (8.5 [dcl.init]) shall be a constant expression.

The phrase “every expression” is intended to cover
multiple arguments to a constexpr constructor and multiple expressions
in an aggregate initializer. However, it could be read (incorrectly)
as saying that non-constant expressions cannot appear as subexpressions
in such initializers, even in places where they do not render the
full-expression non-constant (i.e., as unevaluated operands and in the
unselected branches of &&, ||, and
?:). Perhaps this problem could be remedied by replacing
“every expression” with “every
full-expression?”

Proposed resolution (June, 2008):

Change 7.1.5 [dcl.constexpr] paragraph 7 as follows:

A constexpr specifier used in an object declaration declares
the object as const. Such an object shall be initialized,
and every expression that appears in its initializer (8.5)initialized. If it is initialized by a constructor call, the
constructor shall be a constexpr constructor and every argument to the
constructor shall be a constant expression. Otherwise, every
full-expression that appears in its initializer shall be a
constant expression. Every implicit conversion used...

283.
Template type-parameters are not syntactically type-names

A type-parameter defines its identifier to be a
type-name (if declared with class or
typename)

the grammar in 7.1.6.2 [dcl.type.simple] paragraph 1
says that a type-name is either a class-name, an
enum-name, or a typedef-name. The identifier
in a template type-parameter is none of those. One
possibility might be to equate the identifier with a
typedef-name instead of directly with a type-name,
which would have the advantage of not requiring parallel treatment
of the two in situations where they are treated the same (e.g.,
in elaborated-type-specifiers, see
issue 245). See also
issue 215.

Proposed resolution (Clark Nelson, March 2002):

In 14.1 [temp.param] paragraph 3,
change "A type-parameter defines its identifier to be a
type-name"
to "A type-parameter defines its identifier
to be a typedef-name"

In 7.1.6.3 [dcl.type.elab] paragraph 2,
change "If the identifier resolves to a typedef-name or a template
type-parameter"
to "If the identifier resolves to a typedef-name".

This has been consolidated with the edits for some other
issues. See N1376=02-0034.

516.
Use of signed in bit-field declarations

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.6.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 andchar objects and
bit-fields to be signed; it is redundant with other integral
typesin other contexts. —end note]

otherwise, if e is a function call (5.2.2 [expr.call]) or an invocation of an overloaded operator
(parentheses around e are ignored), decltype(e) is
the return type of that function;

The reference to “that function” is imprecise; it is
not the actual function called at runtime but the statically chosen
function (ignoring covariant return types in virtual functions).

Also, the examples in this paragraph have errors:

The declaration of struct A should end with a
semicolon.

The lines of the form decltype(...); are ill-formed;
they need a declarator.

Proposed Resolution (October, 2007):

Change 7.1.6.2 [dcl.type.simple] paragraph 4 as follows:

The type denoted by decltype(e) is defined as follows:

if e is an id-expression or a class member
access (5.2.5 [expr.ref]), decltype(e) is the type
of the entity named by e. If there is no such entity, or
if e names a set of overloaded functions, the program is
ill-formed;

otherwise, if e is a function call (5.2.2 [expr.call]) or an invocation of an overloaded operator (parentheses
around e are ignored), decltype(e) is the return
type of thatthe statically chosen function;

otherwise, if e is an lvalue, decltype(e)
is T&, where T is the type of e;

otherwise, decltype(e) is the type
of e.

The operand of the decltype specifier is an unevaluated
operand (clause 5 [expr]).

629.
auto parsing ambiguity

[Voted into the WP at the February, 2008 meeting as paper
J16/08-0056 = WG21 N2546.]

We've found an interesting parsing ambiguity with the new meaning of
auto. Consider:

typedef int T;
void f() {
auto T = 42; // Valid or not?
}

The question here is whether T should be a type specifier or a
storage class? 7.1.6.4 [dcl.spec.auto] paragraph 1 says,

The autotype-specifier has two meanings depending on
the context of its use. In a decl-specifier-seq that contains
at least one type-specifier (in addition to auto) that
is not a cv-qualifier, the autotype-specifier
specifies that the object named in the declaration has automatic
storage duration.

In this case, T is a type-specifier, so the
declaration is ill-formed: there is no declarator-id. Many,
however, would like to see auto work “just like
int,” i.e., forcing T to be redeclared in
the inner scope. Concerns cited included hijacking of the name in
templates and inline function bodies over the course of time if a
program revision introduces a type with that name in the surrounding
context. Although it was pointed out that enclosing the name in
parentheses in the inner declaration would prevent any such
problems, this was viewed as unacceptably ugly.

Notes from the April, 2007 meeting:

The CWG wanted to avoid a rule like, “if auto can
be a type-specifier, it is” (similar to the existing
“if it can be a declaration, it is” rule) because of the
lookahead and backtracking difficulties such an approach would pose
for certain kinds of parsing techniques. It was noted that the
difficult lookahead cases all involve parentheses, which would not
be a problem if only the “=” form of initializer were
permitted in auto declarations; only very limited lookahead
is required in that case. It was also pointed out that the “if
it can be a type-specifier, it is” approach results in a
quiet change of meaning for cases like

typedef int T;
int n = 3;
void f() {
auto T(n);
}

This currently declares n to be an int variable
in the inner scope but would, under the full lookahead approach,
declare T to be a variable, quitely changing uses
of n inside f() to refer to the outer variable.

The consensus of the CWG was to pursue the change to require the
“=” form of initializer for auto.

Notes from the July, 2007 meeting:

See paper J16/07-0197 = WG21 N2337. There was no consensus
among the CWG for either of the approaches recommended in the
paper; additional input and direction is required.

172.
Unsigned int as underlying type of enum

According to 7.2 [dcl.enum]
paragraph 5,
the underlying type of an enum is an unspecified integral type,
which could potentially be unsigned int. The promotion
rules in 4.5 [conv.prom]
paragraph 2 say
that such an enumeration value used in an expression will be promoted
to unsigned int. This means that a conforming
implementation could give the value false for the
following code:

enum { zero };
-1 < zero; // might be false

This is counterintuitive. Perhaps the description of the underlying
type of an enumeration should say that an unsigned underlying type
can be used only if the values of the enumerators cannot be
represented in the corresponding signed type. This approach would
be consistent with the treatment of integral promotion of
bitfields (4.5 [conv.prom]
paragraph 3).

On a related note,
7.2 [dcl.enum]
paragraph 5 says,

the underlying type shall not be larger than int unless
the value of an enumerator cannot fit in an int or
unsigned int.

This specification does not allow for an enumeration like

enum { a = -1, b = UINT_MAX };

Since each enumerator can fit in an int
or unsigned int, the underlying type is required to be
no larger than int, even though there is no such type that
can represent all the enumerators.

Proposed resolution (04/01; obsolete, see below):

Change 7.2 [dcl.enum] paragraph 5 as follows:

It is implementation-defined which integral type is used as
the underlying type for an enumeration except that the
underlying type shall not be larger than int unless
the value of an enumerator cannot fit in an int
or unsigned intneither int nor
unsigned int can represent all the enumerator values.
Furthermore, the underlying type shall not be an unsigned
type if the corresponding signed type can represent all the
enumerator values.

It was noted that 4.5 [conv.prom] promotes unsigned
types smaller than int to (signed) int. The
signedness chosen by an implementation for small underlying types
is therefore unobservable, so the last sentence of the proposed
resolution above should apply only to int and larger
types. This observation also prompted discussion of an
alternative approach to resolving the issue, in which the
bmin and bmax of the enumeration
would determine the promoted type rather than the underlying type.

Proposed resolution (10/01):

Change 4.5 [conv.prom] paragraph 2 from

An rvalue of type wchar_t (3.9.1 [basic.fundamental])
or an enumeration type
(7.2 [dcl.enum]) can be converted to an rvalue of
the first of the following
types that can represent all the values of its underlying type:
int, unsigned int, long, or unsigned long.

to

An rvalue of type wchar_t (3.9.1 [basic.fundamental])
can be converted to an rvalue of the first of the following
types that can represent all the values of its underlying type:
int, unsigned int, long, or unsigned long.
An rvalue of an enumeration type (7.2 [dcl.enum])
can be converted to an rvalue of the first of the following
types that can represent all the values of the enumeration (i.e., the
values in the range bmin to bmax as
described in 7.2 [dcl.enum]):
int, unsigned int, long, or unsigned long.

660.
Unnamed scoped enumerations

The current specification of scoped enumerations does not appear
to forbid an example like the following, even though the enumerator
e cannot be used:

enum class { e };

This might be covered by 7 [dcl.dcl] paragraph 3,

In a simple-declaration, the
optional init-declarator-list can be omitted only when
declaring a class (clause 9 [class]) or enumeration
(7.2 [dcl.enum]), that is, when
the decl-specifier-seq contains either
a class-specifier, an elaborated-type-specifier with a
class-key (9.1 [class.name]), or
an enum-specifier. In these cases and whenever a
class-specifier or enum-specifier is present in the
decl-specifier-seq, the identifiers in these specifiers are
among the names being declared by the declaration
(as class-names, enum-names, or enumerators,
depending on the syntax). In such cases, and except for the
declaration of an unnamed bit-field (9.6 [class.bit]), the
decl-specifier-seq shall introduce one or more names into the
program, or shall redeclare a name introduced by a previous
declaration.

which, when combined with paragraph 2,

A declaration occurs in a scope (3.3 [basic.scope]); the scope
rules are summarized in 3.4 [basic.lookup]. A declaration that
declares a function or defines a class, namespace, template, or
function also has one or more scopes nested within it. These nested
scopes, in turn, can have declarations nested within them. Unless
otherwise stated, utterances in clause 7 [dcl.dcl] about
components in, of, or contained by a declaration or subcomponent
thereof refer only to those components of the declaration that
are not nested within scopes nested within the declaration.

appears to rule out the similar class definition,

struct { int m; };

However, a scoped enumeration is not listed in paragraph 2 among the
constructs containing a nested scope (although 3.3.8 [basic.scope.enum]
does describe “enumeration scope”); furthermore, an
enumerator-definition is not formally a “nested
declaration.” If unusable scoped enumeration definitions are to
be banned, these shortcomings in 7 [dcl.dcl] paragraph 2
must be addressed. (A note in 7.2 [dcl.enum] mentioning that
unnamed scoped enumerations are not allowed would also be helpful.)

Notes from the February, 2008 meeting:

The consensus was to require that the identifier be
present in an enum-specifier unless the enum-key is
enum.

Proposed resolution (June, 2008):

Change 7.2 [dcl.enum] paragraph 2 as follows:

...The enum-keys enum class and enum struct
are semantically equivalent; an enumeration type declared with one of
these is a scoped enumeration, and its enumerators are
scoped enumerators. The optional identifier shall not be
omitted in the declaration of a scoped enumeration. The
type-specifier-seq of an enum-base...

540.
Propagation of cv-qualifiers in reference-to-reference collapse

[Voted into the WP at the October, 2006 meeting as part of
paper J16/06-0188 = WG21 N2118.]

The resolution of issue 106 specifies
that an attempt to create a type “reference to cv1T,” where T is a typedef or template parameter
of the type “reference to cv2S,” actually
creates the type “reference to cv12S,”
where cv12 is the union of the two sets of cv-qualifiers.

One objection that has been raised to this resolution is that it
is inconsistent with the treatment of cv-qualification and references
specified in 8.3.2 [dcl.ref] paragraph 1, which says
that cv-qualifiers applied to a typedef or template argument that is
a reference type are ignored. For example:

In fact, however, these two declarations are quite different. In the
declaration of r1, const applies to a
“top-level” reference, while in the declaration of t2,
it occurs under a reference. In general, cv-qualifiers that appear under
a reference are preserved, even if the type appears in a context in which
top-level cv-qualification is removed, for example, in determining the
type of a function from parameter types (8.3.5 [dcl.fct]
paragraph 3) and in template argument deduction
(14.8.2.1 [temp.deduct.call] paragraph 2).

Another objection to the resolution is that type composition gives
different results in a single declaration than it does when separated
into two declarations. For example:

The initial motivation for the propagation of cv-qualification
during reference-to-reference collapse was to prevent inadvertent
loss of cv-qualifiers in contexts in which it could make a
difference. For example, if the resolution were changed to discard,
rather than propagate, embedded cv-qualification, overload
resolution could surprisingly select a non-const version of a member
function:

On the other hand, those who would like to see the resolution
changed to discard embedded cv-qualifiers observe that these examples
are too simple to be representative of real-world code. In general,
it is unrealistic to expect that a template written with non-reference
type parameters in mind will automatically work correctly with
reference type parameters as a result of applying the issue 106
resolution. Instead, template metaprogramming allows the template
author to choose explicitly whether cv-qualifiers are propagated or
dropped, according to the intended use of the template, and it is more
important to respect the reasonable intuition that a declaration
involving a template parameter will not change the type that the
parameter represents.

As a sample of real-world code, tr1::tuple was examined.
In both cases — the current resolution of issue 106 and one in
which embedded cv-qualifiers were dropped — some metaprogramming
was required to implement the intended interface, although the version
reflecting the revised resolution was somewhat simpler.

Notes from the October, 2005 meeting:

The consensus of the CWG was that the resolution of
issue 106 should be revised not to
propagate embedded cv-qualification.

Note (February, 2006):

The wording included in the rvalue-reference paper,
J16/06-0022 = WG21 N1952, incorporates changes intended to implement
the October, 2005 consensus of the CWG.

11.
How do the keywords typename/template interact with using-declarations?

When the rules for typename and the similar use of template
were decided, we chose to require that they be used at every reference.
The way to avoid 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:

Continue to allow typename in using-declarations, and template
(for member templates) too. Attach the "is a type" or "is a template"
attribute to the placeholder name which the using-declaration "declares"

Disallow typename and template in using-declarations
(just as class-keys are disallowed now). Allow typename
and template before unqualified names which refer to dependent
qualified names through using-declarations.

Document that this is broken.

Suggested Resolution:

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:

When "g" is instantiated, the two declarations of X are compatible
(7.3.3 [namespace.udecl]
paragraph 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:

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.

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.

Tentative Resolution:

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 Core issue 36.

Rationale (04/99): Any semantics associated with the
typename keyword in using-declarations should be considered an
extension.

Notes from the April 2003 meeting:

This was reopened because we are now considering extensions again.
We agreed that it is desirable for the typename to be "sticky" on
a using-declaration, i.e., references to the name introduced by
the using-declaration are known to be type names without the use
of the typename keyword (which can't be specified on an unqualified
name anyway, as of now). The related issue with the template keyword
already has a separate issue 109.

Issue 2 deals with the "struct hack."
There is an example in 7.3.3 [namespace.udecl] paragraph 10
that shows a use of using-declarations to import two names that
coexist because of the "struct hack." After some deliberation,
we decided that the template-dependent using-declaration case is
different enough that we did not have to support the "struct hack"
in that case.
A name introduced in such a case is like a typedef, and no other
hidden type can be accessed through an elaborated type specifier.

Proposed resolution (April 2003, revised October 2003):

Add a new paragraph to the bottom of 7.3.3 [namespace.udecl]:

If a using-declaration uses
the keyword typename and specifies a dependent name
(14.6.2 [temp.dep]), the
name introduced by the using-declaration is treated as a
typedef-name (7.1.3 [dcl.typedef]).

258.
using-declarations and cv-qualifiers

When a using-declaration brings names from a base class into a
derived class scope, member functions in the derived class override
and/or hide member functions with the same name and parameter types in
a base class (rather than conflicting).

Note that this description says nothing about the cv-qualification
of the hiding and hidden member functions. This means, for instance,
that a non-const member function in the derived class hides a const
member function with the same name and parameter types instead of
overloading it in the derived class scope. For example,

If a virtual member function vf is declared in a class
Base and in a class Derived, derived directly or
indirectly from Base, a member function vf with the
same name and same parameter list as Base::vf is declared,
then Derived::vf is also virtual (whether or not it is so
declared) and it overrides Base::vf.

Notes on the 04/01 meeting:

The hiding and overriding should
be on the basis of the function signature, which includes any
cv-qualification on the function.

Proposed resolution (04/02):

In 7.3.3 [namespace.udecl] paragraph 12 change:

When a using-declaration brings names from a base class into a
derived class scope, member functions in the derived class override and/or
hide member functions with the same name and parameter types in a base
class (rather than conflicting).

to read:

When a using-declaration brings names from a base class into a
derived class scope, member functions and member function templates in
the derived class override and/or hide member functions and member
function templates with the same name, parameter-type-list
(8.3.5 [dcl.fct]),
and cv-qualification in a base class (rather than conflicting).

In 10.3 [class.virtual] paragraph 2 change:

If a virtual member function vf is declared in a class
Base and in a class Derived, derived directly or
indirectly from Base, a member function vf with the
same name and same parameter list as Base::vf is declared,
then Derived::vf is also virtual (whether or not it is so
declared) and it overrides Base::vf.

to read:

If a virtual member function vf is declared in a class
Base and in a class Derived, derived directly or
indirectly from Base, a member function vf with the
same name, parameter-type-list (8.3.5 [dcl.fct]), and
cv-qualification as Base::vf
is declared, then Derived::vf is also virtual (whether or not
it is so declared) and it overrides Base::vf.

Several popular compilers give an error on this, but there
doesn't seem to be anything in 7.3.3 [namespace.udecl] that
prohibits it. It should be noted that the user can get the same
effect by using a namespace alias:

namespace my_namespace2 = ::my_namespace::my_namespace2;

Notes from the March 2004 meeting:

We agree that it should be an error.

Proposed resolution (October, 2004):

Add the following as a new paragraph after 7.3.3 [namespace.udecl] paragraph 5:

A using-declaration shall not name a namespace;

4.
Does extern "C" affect the linkage of function names with internal linkage?

At most one of a set of overloaded functions with a particular name
can have C linkage.

Does this apply to static functions as well? For example, is the following
well-formed?

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 [dcl.link]
paragraph 6 doesn't apply.

Suggested 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.

Proposed 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 explicit
linkage to top-level names declared in simple linkage specifications.

The language linkage of any function type formed through a function
declarator is that of the nearest enclosing linkage-specification.
For purposes of determining whether the declaration of a namespace-scope
name matches a previous declaration, the language linkage portion of the
type of a function declaration (that is, the language linkage of the function
itself, not its parameters, return type or exception specification) is
ignored.

For a linkage-specification using braces, i.e.

externstring-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.

externstring-literaldeclaration

the 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.

extern "C++" void f(void(*fp)()); // error - linkage of "f" does not
// match previous declaration
// (linkage of function type used in
// parameter is still "C" and is not
// by itself ill-formed)
extern "C" void g(void(*fp)()); // error - linkage of "g" does not
// match previous declaration
// (linkage of function type used in
// parameter is still "C++" and is not
// by itself ill-formed)

That is, non-top-level declarators get their linkage from matching
declarations, if any, else from the nearest enclosing linkage
specification. (As already described, top-level declarators in a
brace-enclosed linkage specification get the linkage from matching
declarations, if any, else from the linkage specifcation; while
top-level declarators in direct linkage specifications get their
linkage from that specification.)

Mike Miller: This is a pretty significant change from the
current specification, which treats the two forms of language linkage
similarly for most purposes. I don't understand why it's desirable to
expand the differences.

It seems very unintuitive to me that you could have a top-level
declaration in an extern "C" block that would not
receive "C" linkage.

In the current standard, the statement in
7.5 [dcl.link] paragraph 4 that

the specified language linkage applies to the function types of all
function declarators, function names, and variable names introduced by
the declaration(s)

both "C++" declarations would be well-formed, declaring an
overloaded version of f that takes a pointer to a "C++"
function as a parameter. I wouldn't expect that either declaration
would be a redeclaration (valid or invalid) of the "C" version of
f.

Bill Gibbons: The potential difficulty is the matching
process and the handling of deliberate overloading based on language
linkage. In the above examples, how are these two declarations
matched:

given that the linkage that is part of fp1 is "C" while the linkage (prior
to the matching process) that is part of fp2 is "C++"?

The proposal is that the linkage which is part of the parameter type is not
determined until after the match is attempted. This almost always correct
because you can't overload "C" and "C++" functions; so if the function names
match, it is likely that the declarations are supposed to be the
same.

Mike Miller: This seems like more trouble than it's worth.
This comparison of function types ignoring linkage specifications is,
as far as I know, not found anywhere in the current standard. Why do
we need to invent it?

Bill Gibbons: It is possible to construct pathological cases where this fails, e.g.

In this case the two function declarations refer to different
functions.

Mike Miller: This seems pretty strange to me. I think it
would be simpler to determine the type of the parameter based on the
containing linkage specification (implicitly "C++") and require a
typedef if the user wants to override the default behavior. For
example:

The following changes were tentatively approved, but because they
do not completely implement the proposal above the issue is being kept
for the moment in "drafting" status.

Notes from 10/00 meeting:

After further discussion, the core language working group
determined that the more extensive proposal described above is
not needed and that the following changes are sufficient.

Proposed resolution (04/01):

Change the first sentence of 7.5 [dcl.link]
paragraph 1 from

All function types, function names, and variable names
have a language linkage.

to

All function types, function names with external
linkage, and variable names with external linkage have
a language linkage.

Change the following sentence of 7.5 [dcl.link]
paragraph 4:

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).

to

In a linkage-specification, the specified language
linkage applies to the function types of all function
declarators, function names with external linkage, and
variable names with external linkage declared within
the linkage-specification.

Except for functions with internal linkage, a function
first declared in a linkage-specification behaves as a
function with external linkage. [Example:

extern "C" double f();
static double f(); // error

is ill-formed (7.1.1 [dcl.stc]). ] The form of
linkage-specification that contains a braced-enclosed
declaration-seq does not affect whether the contained
declarations are definitions or not (3.1 [basic.def]); the
form of linkage-specification directly containing a
single declaration is treated as an extern specifier
(7.1.1 [dcl.stc]) for the purpose of determining whether
the contained declaration is a definition. [Example:

extern "C" int i; // declaration
extern "C" {
int i; // definition
}

—end example] A linkage-specification directly
containing a single declaration shall not specify a
storage class. [Example:

extern "C" static void f(); // error

—end example]

to

A declaration directly contained in a
linkage-specification is treated as if it contains the
extern specifier (7.1.1 [dcl.stc]) for the purpose of
determining the linkage of the declared name and
whether it is a definition. Such a declaration shall
not specify a storage class. [Example:

29.
Linkage of locally declared functions

[Moved to DR at October 2002 meeting. This was incorrectly
marked as having DR status between 4/01 and 4/02. It was overlooked
when issue 4 was moved to DR at the 4/01
meeting; this one should have been moved as well, because it's resolved
by the changes there.]

Consider the following:

extern "C" void foo()
{
extern void bar();
bar();
}

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?

From Mike Miller:

Yes: from 7 [dcl.dcl]
paragraph 1,

declaration:

function-definition

and 8.4 [dcl.fct.def]
paragraph 1:

function-definition:

decl-specifier-seqopt declarator ctor-initializeropt function-body

At least that's how I'd read it.

From Dag Brück:

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 identical
programs.

The restrictions on declaring and/or defining classes inside
type-specifier-seqs and type-ids are inconsistent
throughout the Standard. This is probably due to the fact that
nearly all of the sections that deal with them attempt to state
the restriction afresh. There are three cases:

5.3.4 [expr.new], 6.4 [stmt.select],
and 12.3.2 [class.conv.fct] prohibit “declarations”
of classes and enumerations. That means that

while (struct C* p = 0) ;

is ill-formed unless a prior declaration of C has been
seen. These appear to be cases that should have been fixed by
issue 379, changing “class
declaration” to “class definition,” but were
overlooked.

All the remaining cases prohibit “type
definitions,” apparently referring to classes and
enumerations.

Suggested resolution:

Add something like, “A class or enumeration shall
not be defined in a type-specifier-seq or in a
type-id,” to a single place in the Standard and
remove all other mentions of that restriction (allowing
declarations via elaborated-type-specifier).

Mike Miller:

An alias-declaration is just a different syntax for
a typedef declaration, which allows definitions of a class in
the type; I would expect the same to be true of an
alias-declaration. I don't have any particularly
strong attachment to allowing a class definition in an
alias-declaration. My only concern is introducing
an irregularity into what are currently exact-match
semantics with typedefs.

There's a parallel restriction in many (but not all?) of
these places on typedef declarations.

Jens Maurer:

Those are redundant, as typedef is not a
type-specifier, and should be removed as well.

The type-specifier-seq shall not contain class declarations, or
enumeration declarations.

Delete paragraph 4 of 5.3.6 [expr.alignof]:

A type shall not be defined in an alignof expression.

Delete paragraph 3 of 5.4 [expr.cast]:

Types shall not be defined in casts.

Delete the indicated words from 6.4 [stmt.select]
paragraph 2:

...The type-specifier-seq shall not contain
typedef and shall not declare a new class or
enumeration....

Add the indicated words to 7.1.6 [dcl.type]
paragraph 3:

At least one type-specifier that is not a
cv-qualifier is required in a declaration unless it
declares a constructor, destructor or conversion function.
[Footnote: ... ] A type-specifier-seq shall not
define a class or enumeration unless it appears in the
type-id of an alias-declaration
(7.1.3 [dcl.typedef]).

Delete the indicated words from 12.3.2 [class.conv.fct]
paragraph 1:

...Classes, enumerations, and typedef-names shall not be
declared in the type-specifier-seq....

In
3.7.4.1 [basic.stc.dynamic.allocation]
paragraph 4, replace "type_info" by
"std::type_info" in the note.

In
3.7.4.2 [basic.stc.dynamic.deallocation]
paragraph 3, replace all four instances of "size_t" by
"std::size_t".

In
3.8 [basic.life]
paragraph 5, replace "malloc" by
"std::malloc" in the example code and insert
"#include <cstdlib>" at the beginning of the example
code.

In
3.9 [basic.types]
paragraph 2, replace "memcpy" by
"std::memcpy" (the only instance in the footnote and both
instances in the example) and replace "memmove" by
"std::memmove" in the footnote (see also
issue 43).

In
3.9 [basic.types]
paragraph 3, replace "memcpy" by
"std::memcpy", once in the normative text and once in the
example (see also issue 43).

In
15.4 [except.spec]
paragraph 9, replace "unexpected" by
"std::unexpected" and "terminate" by
"std::terminate".

In
15.5 [except.special]
paragraph 1, replace "terminate" by
"std::terminate" and "unexpected" by
"std::unexpected".

In the heading of
15.5.1 [except.terminate],
replace "terminate" by "std::terminate".

In
15.5.1 [except.terminate]
paragraph 1, footnote in the first bullet, replace
"terminate" by "std::terminate". In the
same paragraph, fifth bullet, replace "atexit" by
"std::atexit". In the same paragraph, last bullet,
replace "unexpected_handler" by
"std::unexpected_handler".

In
15.5.1 [except.terminate]
paragraph 2, replace

In such cases,

void terminate();

is called...

by

In such cases, std::terminate() is called...

and replace all three instances of "terminate" by
"std::terminate".

In the heading of
15.5.2 [except.unexpected],
replace "unexpected" by "std::unexpected".

In
15.5.2 [except.unexpected]
paragraph 1, replace

...the function

void unexpected();

is called...

by

...the function std::unexpected() is called...

.

In
15.5.2 [except.unexpected]
paragraph 2, replace "unexpected" by
"std::unexpected" and "terminate" by
"std::terminate".

—end example]
[Note: an "array of Ncv-qualifier-seqT"
has cv-qualified type; such
an array has internal linkage unless explicitly declared extern
(7.1.6.1 [dcl.type.cv]
)
and must be initialized as specified in
8.5 [dcl.init]
. ]

The Note appears to contradict the sentence that precedes it.

Mike Miller:
I disagree; all it says is that whether the qualification on
the element type is direct ("const int x[5]") or indirect
("const A CA"), the array itself is qualified in the same way
the elements are.

A compound type (3.9.2 [basic.compound]
)
is not cv-qualified by the cv-qualifiers (if
any) of the types from which it is compounded. Any cv-qualifiers
applied to an array type affect the array element type, not the
array type (8.3.4 [dcl.array]
)."

The Note appears to contradict that section as well.

Mike Miller:
Yes, but consider the last two sentences of
3.9.3 [basic.type.qualifier]
paragraph 5:

Cv-qualifiers applied to an array type attach to the
underlying element type, so the notation "cvT,"
where T is
an array type, refers to an array whose elements are
so-qualified. Such array types can be said to be more (or
less) cv-qualified than other types based on the cv-qualification
of the underlying element types.

I think this says essentially the same thing as
8.3.4 [dcl.array]
paragraph 1 and
its note: the qualification of an array is (bidirectionally)
equivalent to the qualification of its members.

Mike Ball:
I find this a very far reach. The text in
8.3.4 [dcl.array]
is essentially that which
is in the C standard (and is a change from early versions of C++).
I don't see any justification at all for the bidirectional equivalence.
It seems to me that
the note is left over from the earlier version of the language.

Steve Clamage: Finally, the Note seems to say that the declaration

volatile char greet[6] = "Hello";

gives "greet" internal linkage, which makes no sense.

Have I missed something, or should that Note be entirely removed?

Mike Miller:
At least the wording in the note
should be repaired not to indicate that volatile-qualification
gives an array internal linkage. Also, depending on how the
discussion goes, either the wording in
3.9.3 [basic.type.qualifier]
paragraph 2
or in paragraph 5 needs
to be amended to be consistent regarding whether an array type
is considered qualified by the qualification of its element
type.

Steve Adamczyk pointed out that
the current state of affairs resulted from the need to handle
reference binding consistently. The wording is intended to define
the question, "Is an array type cv-qualified?" as being equivalent
to the question, "Is the element type of the array cv-qualified?"

Proposed resolution (10/00):

Replace the portion of the note in 8.3.4 [dcl.array]
paragraph 1 reading

such an array has internal linkage unless explicitly declared
extern (7.1.6.1 [dcl.type.cv]) and must be
initialized as specified in 8.5 [dcl.init].

140.
Agreement of parameter declarations

All declarations for a function with a given parameter list shall
agree exactly both in the type of the value returned and in the
number and type of parameters.

It is not clear what this requirement means with respect to a pair
of declarations like the following:

int f(const int);
int f(int x) { ... }

Do they violate this requirement? Is x const in the body of
the function declaration?

Tom Plum:
I think the FDIS quotation means that the pair of decls are valid.
But it doesn't clearly answer whether
x is const inside the function definition.
As to intent, I know the intent was that if the function
definition wants to specify that x is const,
the const must appear specifically in the defining
decl, not just on some decl elsewhere.
But I can't prove that intent from the drafted words.

Mike Miller:
I think the intent was something along the
following lines:

Two function declarations denote the same entity if
the names are the same and the function signatures
are the same. (Two function declarations with C
language linkage denote the same entity if the names
are the same.) All declarations of a given function
shall agree exactly both in the type of the value
returned and in the number and type of parameters;
the presence or absence of the ellipsis is considered
part of the signature.

(See 3.5 [basic.link]
paragraph 9.
That paragraph talks about names in different
scopes and says that function references are the same if the
"types are identical for purposes of overloading," i.e., the
signatures are the same. See also
7.5 [dcl.link]
paragraph 6
regarding C language
linkage, where only the name is required to be the same for
declarations in different namespaces to denote the same
function.)

According to this paragraph, the type of a parameter is
determined by considering its decl-specifier-seq and
declarator
and then applying the array-to-pointer and function-to-pointer
adjustments. The cv-qualifier and storage class adjustments
are performed for the function type but not for the parameter
types.

If my interpretation of the intent of the second sentence of
the paragraph is correct, the two declarations in the example
violate that restriction — the parameter types are not the
same, even though the function types are. Since there's no
dispensation mentioned for "no diagnostic required," an
implementation presumably must issue a diagnostic in this
case. (I think "no diagnostic required" should be stated if
the declarations occur in different translation units —
unless there's a blanket statement to that effect that I have
forgotten?)

(I'd also note in passing that, if my interpretation is
correct,

void f(int);
void f(register int) { }

is also an invalid pair of declarations.)

Proposed resolution (10/00):

In 1.3 [intro.defs] “signature,” change
"the types of its parameters"
to
"its parameter-type-list (8.3.5 [dcl.fct])".

In the third bullet of 3.5 [basic.link] paragraph 9
change
"the function types are identical for the purposes of overloading"
to
"the parameter-type-lists of the functions (8.3.5 [dcl.fct]) are identical."

In the sub-bullets of the third bullet of
5.2.5 [expr.ref] paragraph 4, change all four occurrences
of
"function of (parameter type list)"
to
"function of parameter-type-list."

In 8.3.5 [dcl.fct] paragraph 3, change

All declarations for a function with a given parameter list shall agree
exactly both in the type of the value returned and in the number and
type of parameters; the presence or absence of the ellipsis is
considered part of the function type.

to

All declarations for a function shall
agree exactly in both the return type and the
parameter-type-list.

In 8.3.5 [dcl.fct] paragraph 3, change

The resulting list of transformed parameter types is the function's
parameter type list.

to

The resulting list of transformed parameter types and the presence or
absence of the ellipsis is the function's parameter-type-list.

In 8.3.5 [dcl.fct] paragraph 4, change
"the parameter type list"
to
"the parameter-type-list."

In the second bullet of 13.1 [over.load] paragraph 2,
change all occurrences of "parameter types" to
"parameter-type-list."

In 13.3 [over.match] paragraph 1, change "the types of
the parameters" to "the parameter-type-list."

In the last sub-bullet of the third bullet of
13.3.1.2 [over.match.oper] paragraph 3, change "parameter type
list" to "parameter-type-list."

Note, 7 Sep 2001:

Editorial changes while putting in issue 147
brought up the fact that injected-class-name is not a syntax term and
therefore perhaps shouldn't be written with hyphens. The same can be said of
parameter-type-list.

in the instantiation of foo, T is `void ()' and an attempt
is made to const qualify that, which is ill-formed. This is a surprise.

Suggested resolution:

Replace the quoted sentence from paragraph 4 in
8.3.5 [dcl.fct] with

cv-qualified functions are ill-formed, except when the
cv-qualifiers are introduced through the use of a typedef or of
a template type argument, in which case the cv-qualifiers are
ignored.

Adjust the example following to reflect this.

Proposed resolution (10/01):

In 8.3.5 [dcl.fct] paragraph 4, replace

The effect of a cv-qualifier-seq in a function declarator is
not the same as adding cv-qualification on top of the function type,
i.e., it does not create a cv-qualified function type. In fact, if at
any time in the determination of a type a cv-qualified function type
is formed, the program is ill-formed. [Example:

typedef void F();
struct S {
const F f; // ill-formed
};

-- end example]

by

The effect of a cv-qualifier-seq in a function declarator is
not the same as adding cv-qualification on top of the function type.
In the latter case, the cv-qualifiers are ignored. [Example:

Strike the last bulleted item in 14.8.2 [temp.deduct]
paragraph 2, which reads

Attempting to create a cv-qualified function type.

Nathan Sidwell comments (18 Dec 2001
):
The proposed resolution simply states attempts to add cv qualification
on top of a function type are ignored. There is no mention of whether
the function type was introduced via a typedef or template type parameter.
This would appear to allow

void (const *fptr) ();

but, that is not permitted by the grammar. This is inconsistent
with the wording of adding cv qualifiers to a reference type, which does
mention typedefs and template parameters, even though

int &const ref;

is also not allowed by the grammar.

Is this difference intentional? It seems needlessly confusing.

Notes from 4/02 meeting:

Yes, the difference is intentional. There is no way to add cv-qualifiers
other than those cases.

Notes from April 2003 meeting:

Nathan Sidwell pointed out that some libraries use the inability to
add const to a type T as a way of testing that T is a function
type. He will get back to us if he has a proposal for a change.

and the type of the contained declarator-id in the
declaration T D1 is
“derived-declarator-type-listT,” T
shall be the single type-specifierauto and the
derived-declarator-type-list shall be empty.

These restrictions were intended to ensure that the return type of
the function is exactly the specified type-id following the
->, not modified by declarator operators and
cv-qualification.

Unfortunately, the requirement for an empty
derived-declarator-type-list does not achieve this goal but
instead forbids declarations like

auto (*fp)() -> int; // pointer to function returning int

while allowing declarations like

auto *f() -> int; // function returning pointer to int

The reason for this is that, according to the grammar in
8 [dcl.decl] paragraph 4, the declarator *f() -> int
is parsed as a ptr-operator applied to the direct-declaratorf() -> int; that is, the declarator D1 seen in
8.3.5 [dcl.fct] is just f, and the
derived-declarator-type-list is thus empty.

By contrast, the declarator (*fp)() -> int is parsed
as the direct-declarator(*fp) followed by the
parameter-declaration-clause, etc. In this case, D1 in
8.3.5 [dcl.fct] is (*fp) and the
derived-declarator-type-list is “pointer to,” i.e.,
not empty.

My personal view is that there is no reason to forbid the
(*fp)() -> int form, and that doing so is problematic.
For example, this restriction would require users desiring the
late-specified return type syntax to write function parameters as
function types and rely on parameter type transformations rather
than writing them as pointer-to-function types, as they will actually
turn out to be:

It may be helpful in deciding whether to allow this form to
consider the example of a function returning a pointer to a function.
With the current restriction, only one of the three plausible forms is
allowed:

... T shall be the single type-specifierautoand the derived-declarator-type-list shall be
empty. Then the type...

Change all occurrences of direct-new-declarator in
5.3.4 [expr.new] to noptr-new-declarator. These
changes appear in the grammar in paragraph 1 and in the text of
paragraphs 6-8, as follows:

...new-declarator:

ptr-operator new-declaratoroptdirect-noptr-new-declarator

direct-noptr-new-declarator:

[expression]direct-noptr-new-declarator[constant-expression]

...

When the allocated object is an array (that is, the
direct-noptr-new-declarator syntax is used or the
new-type-id or type-id denotes an array type), the
new-expression yields a pointer to the initial element (if any)
of the array. [Note: both new int and new
int[10] have type int* and the type of new
int[i][10] is int (*)[10] —end note]

Every constant-expression in a
direct-noptr-new-declarator shall be an integral
constant expression (5.19 [expr.const]) and evaluate to a
strictly positive value. The expression in a
direct-noptr-new-declarator shall be of integral
type, enumeration type, or a class type for which a single
non-explicit conversion function to integral or enumeration type
exists (12.3 [class.conv]). If the expression is of class
type, the expression is converted by calling that conversion function,
and the result of the conversion is used in place of the original
expression. If the value of the expression is negative, the behavior
is undefined. [Example: given the definition int n =
42, new float[n][5] is well-formed (because n
is the expression of a
direct-noptr-new-declarator), but new
float[5][n] is ill-formed (because n is not a constant
expression). If n is negative, the effect of new float[n][5]
is undefined. —end example]

When the value of the expression in a
direct-noptr-new-declarator is zero, the
allocation function is called to allocate an array with no
elements.

136.
Default arguments and friend declarations

For non-template functions, default arguments can be added in later
declarations of a function in the same scope. Declarations in
different scopes have completely distinct sets of default arguments.
That is, declarations in inner scopes do not acquire default arguments
from declarations in outer scopes, and vice versa.

It is unclear how this wording applies to friend function declarations.
For example,

Does the declaration at #2 acquire the default argument from #1, and
does the one at #3 acquire the default arguments from #2?

There are several related questions involved with this issue:

Is the friend
declaration in the scope of class C or in the surrounding namespace
scope?

Mike Miller:
8.3.6 [dcl.fct.default]
paragraph 4
is speaking about the lexical location of the
declaration...
The friend declaration occurs in a different declarative region
from the declaration at #1, so I would read [this paragraph] as saying that it
starts out with a clean slate of default arguments.

Bill Gibbons:
Yes. It occurs in a different region, although it declares a name
in the same region (i.e. a redeclaration). This is the same as with
local externs and is intended to work the same way. We decided that
local extern declarations cannot add (beyond the enclosing block) new
default arguments, and the same should apply to friend declarations.

John Spicer:
The question is whether [this paragraph]
does (or should) mean declarations that appear in the same lexical
scope or declarations that declare names in the same scope. In my opinion,
it really needs to be the latter. It seems somewhat paradoxical to say
that a friend declaration declares a function in namespace scope yet the
declaration in the class still has its own attributes. To make that work
I think you'd have to make friends more like block externs that really do
introduce a name into the scope in which the declaration is contained.

Should default arguments be permitted in friend function
declarations, and what effect should they have?

Bill Gibbons:
In the absence of a declaration visible in class scope to which
they could be attached, default arguments on friend declarations
do not make sense.
[They should be] ill-formed, to prevent surprises.

In other words, a function first declared in a friend declaration must be
permitted to have default arguments and those default arguments must be
usable when the function is found by argument dependent lookup. The reason
that this is important is that it is common practice to define functions
in friend declarations in templates, and that definition is the only place
where the default arguments can be specified.

What restrictions should be placed on default argument usage with
friend declarations?

John Spicer:
We want to avoid instantiation side effects. IMO, the way to do this
would be to prohibit a friend declaration from providing default arguments
if a declaration of that function is already visible.
Once a function has had a default specified in a friend
declaration it should not be possible to add defaults in another declaration
be it a friend or normal declaration.

Mike Miller:
The position that seems most reasonable to me is to
allow default arguments in friend declarations to be used in
Koenig lookup, but to say that they are
completely unrelated to default arguments in declarations in
the surrounding scope; and to forbid use of a default argument
in a call if more than one declaration in the overload set has
such a default, as in the proposed resolution for
issue 1.

5.
CV-qualifiers and type conversions

The description of copy-initialization in 8.5 [dcl.init]
paragraph 14 says:

If the destination type is a (possibly cv-qualified) class type:
...

Otherwise (i.e. for the remaining copy-initialization cases), user-defined
conversion sequences that can convert from the source type to the destination
type or (when a conversion function is used) to a derived class thereof
are enumerated ... if the function is a constructor, the call initializes
a temporary of the destination type. ...

Should "destination type" in this last bullet refer to "cv-unqualified
destination type" to make it clear that the destination type excludes any
cv-qualifiers? This would make it clearer that the following example is
well-formed:

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.

Steve Adamczyk:

Because of late changes to this area, the
relevant text is now the third sub-bullet of the fourth bullet of
8.5 [dcl.init] paragraph 14:

Otherwise (i.e., for the remaining copy-initialization cases),
user-defined conversion sequences that can convert from the source
type to the destination type or (when a conversion function is used)
to a derived class thereof are enumerated...
The function selected is called with the initializer expression as its
argument; if the function is a constructor, the call initializes a
temporary of the destination type. The result of the call (which is
the temporary for the constructor case) is then used to
direct-initialize, according to the rules above, the object that is
the destination of the copy-initialization.

The issue still remains whether the wording should refer to "the
cv-unqualified version of the destination type." I think it
should.

Notes from 10/00 meeting:

The original example does not illustrate the remaining
problem. The following example does:

78.
Section 8.5 paragraph 9 should state it only applies to non-static objects

If no initializer is specified for an object, and the object
is of (possibly cv-qualified) non-POD class type (or array thereof), the
object shall be default-initialized; if the object is of const-qualified
type, the underlying class type shall have a user-declared default constructor.
Otherwise, if no initializer is specified for an object, the object and
its subobjects, if any, have an indeterminate initial value; if the object
or any of its subobjects are of const-qualified type, the program is ill-formed.

It should be made clear that this paragraph does not apply to static objects.

According to 8.5 [dcl.init]
paragraph
14, the initialization of a is performed in two steps.
First, a temporary of type A is created using A::A(const
B&). Second, the resulting temporary is used to
direct-initialize a using A::A(A&).

The second step requires binding a reference to non-const to the
temporary resulting from the first step. However,
8.5.3 [dcl.init.ref]
paragraph 5 requires
that such a reference be bound only to lvalues.

It is not clear from 3.10 [basic.lval]
whether the temporary created in the process of copy-initialization
should be treated as an lvalue or an rvalue. If it is an lvalue, the
example is well-formed, otherwise it is ill-formed.

Proposed resolution (04/01):

In 8.5 [dcl.init] paragraph 14, insert
the following after "the call initializes a temporary of
the destination type":

277.
Zero-initialization of pointers

The intent of 8.5 [dcl.init] paragraph 5 is that
pointers that are zero-initialized will contain a null pointer
value. Unfortunately, the wording used,

...set to the value of 0 (zero) converted to T

does not match the requirements for creating a null pointer
value given in 4.10 [conv.ptr] paragraph 1:

A null pointer constant is an integral constant expression
(5.19 [expr.const]) rvalue of integer type that evaluates to
zero. A null pointer constant can be converted to a pointer type; the
result is the null pointer value of that type...

The problem is that the "value of 0" in the description of
zero-initialization is not specified to be an integral constant
expression. Nonconstant expressions can also have the value 0,
and converting a nonconst 0 to pointer type need not result in
a null pointer value.

Proposed resolution (04/01):

In 8.5 [dcl.init] paragraph 5, change

...set to the value 0 (zero) converted to T;

to

...set to the value 0 (zero), taken as an integral constant
expression, converted to T; [footnote: as
specified in 4.10 [conv.ptr], converting an integral
constant expression whose value is 0 to a pointer type results
in a null pointer value.]

302.
Value-initialization and generation of default constructor

We've been looking at implementing value-initialization. At one point,
some years back, I remember Bjarne saying that something like X() in
an expression should produce an X object with the same value one would
get if one created a static X object, i.e., the uninitialized members
would be zero-initialized because the whole object is initialized
at program startup, before the constructor is called.

The formulation for default-initialization that made it into TC1 (in
8.5 [dcl.init])
is written a little differently (see issue 178),
but I had always
assumed that it would still be a valid implementation to zero the whole
object and then call the default constructor for the troublesome
"non-POD but no user-written constructor" cases.

That almost works correctly, but I found a problem case:

struct A {
A();
~A();
};
struct B {
// B is a non-POD with no user-written constructor.
// It has a nontrivial generated constructor.
const int i;
A a;
};
int main () {
// Value-initializing a "B" doesn't call the default constructor for
// "B"; it value-initializes the members of B. Therefore it shouldn't
// cause an error on generation of the default constructor for the
// following:
new B();
}

If the definition of the B::B() constructor is generated, an error
is issued because the const member "i" is not initialized. But the
definition of value-initialization doesn't require calling the
constructor, and therefore it doesn't require generating it, and
therefore the error shouldn't be detected.

So this is a case where zero-initializing and then calling the constructor
is not equivalent to value-initializing, because one case generates
an error and the other doesn't.

This is sort of unfortunate, because one doesn't want to generate all
the required initializations at the point where the "()"
initialization
occurs. One would like those initializations to be packaged in a
function, and the default constructor is pretty much the function
one wants.

I see several implementation choices:

Zero the object, then call the default generated constructor. This
is not valid unless the standard is changed to say that the default
constructor might be generated for value-initialization cases like the
above (that is, it's implementation-dependent whether the constructor
definition is generated). The zeroing operation can of course be
optimized, if necessary, to hit only the pieces of the object that
would otherwise be left uninitialized. An alternative would be
to require generation of the constructor for value-initialization
cases, even if the implementation technique doesn't call the
constructor at that point. It's pretty likely that the constructor
is going to have to be generated at some point in the program anyway.

Make a new value-initialization "constructor," whose body looks a
lot like the usual generated constructor, but which also zeroes other members.
No errors would be generated while generating this modified constructor,
because it generates code that does full initialization. (Actually,
it wouldn't guarantee initialization of reference members, and that
might be an argument for generating the constructor, in order to get that
error.) This is standard-conforming, but it destroys object-code
compatibility.

Variation on (1): Zero first, and generate the object code for the
default constructor when it's needed for value-initialization cases, but
don't issue any errors at that time. Issue the errors only if it turns
out the constructor is "really" referenced. Aside from the essential
shadiness of this approach, I fear that something in the generation
of the constructor will cause a template instantiation which will be
an abservable side effect.

Personally, I find option 1 the least objectionable.

Proposed resolution (10/01):

Add the indicated wording to the third-to-last sentence of
3.2 [basic.def.odr] pararaph 2:

A default constructor for a class is used by default initialization
or value initialization as specified in 8.5 [dcl.init].

Add a footnote to the indicated bullet in 8.5 [dcl.init]
paragraph 5:

if T is a non-union class type without a user-declared constructor,
then every non-static data member and base-class component of T is
value-initialized.
[Footnote: Value-initialization for such a class object may be
implemented by zero-initializing the object and then calling the default
constructor.]

Add the indicated wording to the first sentence of
12.1 [class.ctor] paragraph 7:

An implicitly-declared default constructor for a class is implicitly
defined when it is used (3.2 [basic.def.odr]) to
create an object of its class type
(1.8 [intro.object]).

if T is a non-POD class type (clause 9 [class]), the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default
constructor);

if T is an array type, each element is
default-initialized;

otherwise, the object is zero-initialized.

However, default initialization is invoked only for non-POD class
types and arrays thereof (5.3.4 [expr.new] paragraph 15
for new-expressions, 8.5 [dcl.init] paragraph 10
for top-level objects, and 12.6.2 [class.base.init] paragraph 4
for member and base class subobjects — but see
issue 510). Consequently, all cases that
invoke default initialization are handled by the first two bullets;
the third bullet can never be reached. Its presence is misleading, so
it should be removed.

Notes from the September, 2008 meeting:

The approach adopted in the resolution in paper N2762 was
different from the suggestion above: it changes the definition of
default initialization to include POD types and changes the third
bullet to specify that “no initialization is
performed.”

543.
Value initialization and default constructors

[Voted into the WP at the September, 2008 meeting (resolution
in paper N2762).]

The wording resulting from the resolution of
issue 302 does not quite implement the intent
of the issue. The revised wording of 3.2 [basic.def.odr]
paragraph 2 is:

A default constructor for a class is used by default initialization or
value initialization as specified in 8.5 [dcl.init].

This sounds as if 8.5 [dcl.init] specifies how and
under what circumstances value initialization uses a default
constructor (which was, in fact, the case for default initialization
in the original wording). However, the normative text there makes it
plain that value initialization does not call the default
constructor (the permission granted to implementations to call the
default constructor for value initialization is in a non-normative
footnote).

The example that occasioned this observation raises an
additional question. Consider:

struct POD {
const int x;
};
POD data = POD();

According to the (revised) resolution of issue 302, this code is
ill-formed because the implicitly-declared default constructor will
be implicitly defined as a result of being used by value initialization
(12.1 [class.ctor] paragraph 7), and the implicitly-defined
constructor fails to initialize a const-qualified member
(12.6.2 [class.base.init] paragraph 4). This seems unfortunate,
because the (trivial) default constructor of a POD class is otherwise
not used — default initialization applies only to non-PODs
— and it is not actually needed in value initialization.
Perhaps value initialization should be defined to “use”
the default constructor only for non-POD classes? If so, both of
these problems would be resolved by rewording the above-referenced
sentence of 3.2 [basic.def.odr] paragraph 2 as:

A default constructor for a non-POD class is used by
default initialization or value initialization as specified in(8.5 [dcl.init]).

Notes from the April, 2006 meeting:

The approach favored by the CWG was to leave 3.2 [basic.def.odr]
unchanged and to add normative wording to 8.5 [dcl.init]
indicating that it is unspecified whether the default constructor is
called.

Notes from the October, 2006 meeting:

The CWG now prefers that it should not be left unspecified whether
programs of this sort are well- or ill-formed; instead, the Standard
should require that the default constructor be defined in such cases.
Three possibilities of implementing this decision were discussed:

Change 3.2 [basic.def.odr] to state flatly that the
default constructor is used by value initialization (removing the
implication that 8.5 [dcl.init] determines the conditions
under which it is used).

Change 8.5 [dcl.init] to specify that non-union
class objects with no user-declared constructor are value-initialized
by first zero-initializing the object and then calling the
(implicitly-defined) default constructor, replacing the current
specification of value-initializing each of its sub-objects.

Add a normative statement to 8.5 [dcl.init] that
value-initialization causes the implicitly-declared default constructor
to be implicitly defined, even if it is not called.

Proposed resolution (June, 2008):

Change the second bullet of the value-initialization definition
in 8.5 [dcl.init] paragraph 5 as follows:

if T is a non-union class type without a
user-provided constructor, then every non-static data member and
base-class component of T is value-initialized;
[Footnote: Value-initialization for such a class object may be
implemented by zero-initializing the object and then calling the
default constructor. —end footnote]the object is
zero-initialized and the implicitly-defined default constructor is
called;

Notes from the September, 2008 meeting:

The resolution supplied in paper N2762 differs from the June,
2008 proposed resolution in that the implicitly-declared default
constructor is only called (and thus defined) if it is
non-trivial, making the struct POD example above
well-formed.

is this undefined or unspecified or something else? I can find nothing in
8.5.1 [dcl.init.aggr] that indicates whether the components of
an initializer-list are evaluated in order or not, or whether they
have sequence points between them.

6.7.8/23 of the C99 std has this to say

The order in which any side effects occur among the initialization list
expressions is unspecified.

I think similar wording is needed in 8.5.1 [dcl.init.aggr]

Steve Adamczyk:
I believe the standard is clear that each initializer
expression in the above is a full-expression
(1.9 [intro.execution]/12-13; see also
issue 392) and therefore there is a sequence point
after each expression (1.9 [intro.execution]/16). I agree that the
standard does not seem to dictate the order in which the expressions
are evaluated, and perhaps it should. Does anyone know of a compiler
that would not evaluate the expressions left to right?

Mike Simons: Actually there is one, that does not do
left to right: gcc/C++. None of the post increment operations
take effect until after the statement finishes. So in the sample
code gcc stores 23 into all positions in the array. The
commercial vendor C++ compilers for AIX, Solaris, Tru64, HPUX
(parisc and ia64), and Windows, all do sequence points at each
',' in the initializer list.

491.
Initializers for empty-class aggregrate members

The current wording of 8.5.1 [dcl.init.aggr] paragraph
8 requires that

An initializer for an aggregate member that is an empty class
shall have the form of an empty initializer-list {}.

This is overly constraining. There is no reason that the
following should be ill-formed:

struct S { };
S s;
S arr[1] = { s };

Mike Miller: The wording of 8.5.1 [dcl.init.aggr] paragraph 8 is unclear. “An aggregate
member” would most naturally mean “a member of an
aggregate.” In context, however, I think it must mean
“a member [of an aggregate] that is an aggregate”,
that is, a subaggregate. Members of aggregates need not
themselves be aggregates (cf paragraph 13 and 12.6.1 [class.expl.init]); it cannot be the case that an object of an
empty class with a user-declared constructor must be initialized
with {} when it is a member of an aggregate. This
wording should be clarified, regardless of the decision on
Nathan's point.

in which the initializer of a scalar member of an aggregate can
itself be brace-enclosed. The relevant wording from the C99
Standard is found in 6.7.8 paragraph 11:

The initializer for a scalar shall be a single expression,
optionally enclosed in braces.

and paragraph 16:

Otherwise, the initializer for an object that has aggregate or
union type shall be a brace-enclosed list of initializers for the
elements or named members.

The “list of initializers” in paragraph 16 must be
a recursive reference to paragraph 11 (that's the only place that
describes how an initialized item gets its value from the
initializer expression), which would thus make the
“brace-enclosed” part of paragraph 11 apply to each of
the initializers in the list in paragraph 16 as well.

This appears to be an incompatibility between C and C++:
8.5.1 [dcl.init.aggr] paragraph 11 says,

If the initializer-list begins with a left brace, then the
succeeding comma-separated list of initializer-clauses
initializes the members of a subaggregate....

which clearly leaves the impression that only a subaggregate
may be initialized by a brace-enclosed initializer-clause.

Either the specification in 8.5.1 [dcl.init.aggr]
should be changed to allow a brace-enclosed initializer of a
scalar member of an aggregate, as in C, or this incompatibility
should be listed in Appendix C [diff].

Notes from the July, 2007 meeting:

It was noted that implementations differ in their handling of this
construct; however, the issue is long-standing and fairly obscure.

Notes from the October, 2007 meeting:

The initializer-list proposal will resolve this issue when it is
adopted.

There is a place in the Standard where overload resolution is implied
but the way that a set of candidate functions is to be formed is
omitted. See below.

According to the Standard, when initializing a reference to a
non-volatile const class type (cv1T1) with an rvalue
expression (cv2T2) where cv1T1 is
reference compatible with cv2T2, the implementation
shall proceed in one of the following
ways (except when initializing the implicit object parameter of a
copy constructor) 8.5.3 [dcl.init.ref] paragraph 5 bullet 2
sub-bullet 1:

The reference is bound to the object represented by the rvalue (see
3.10 [basic.lval]) or to a sub-object within that object.

A temporary of type "cv1T2" [sic] is created, and a
constructor is called to copy the entire rvalue object into the temporary...

While the first case is quite obvious, the second one is a bit unclear
as it says "a constructor is called to copy the entire rvalue object
into the temporary" without specifying how the temporary is created --
by direct-initialization or by copy-initialization? As stated in DR
152, this can make a difference when the copy constructor is declared
as explicit. How should the set of candidate functions be formed? The
most appropriate guess is that it shall proceed as per
13.3.1.3 [over.match.ctor].

Another detail worth of note is that in the draft version of the
Standard as of 2 December 1996 the second bullet read:

A temporary of type "cv1T2" [sic] is created, and a copy
constructor is called to copy the entire rvalue object into the
temporary...

J. Stephen Adamczyk replied that the reason for changing "a copy
constructor" to "a constructor" was to allow for member template
converting constructors.

However, the new wording is somewhat in conflict with the footnote #93
that says that when initializing the implicit object parameter of a
copy constructor an implementation must eventually choose the first
alternative (binding without copying) to avoid infinite recursion.
This seems to suggest that a copy constructor is always used for
initializing the temporary of type "cv1T2".

Furthermore, now that the set of candidate functions is not limited to
only the copy constructors of T2, there might be some unpleasant
consequences.
Consider a rather contrived sample below:

In this example the initialization of the temporary of type
'<TT>const std::auto_ptr<int>'
(to which 'ri' is meant to be subsequently bound)
doesn't fail, as it would had the approach with copy constructors been
retained, instead, a yet another temporary gets created as the
well-known sequence:

is called (assuming, of course, that the set of candidate functions is
formed as per 13.3.1.3 [over.match.ctor]). The second temporary
is transient and gets
destroyed at the end of the initialization. I doubt that this is the
way that the committee wanted this kind of reference binding to go.

Besides, even if the approach restricting the set of candidates to copy
constructors is restored, it is still not clear how the initialization
of the temporary (to which the reference is intended to be bound) is
to be performed -- using direct-initialization or copy-initialization.

Another place in the Standard that would benefit from a similar
clarification is the creation of an exception object, which is
delineated in 15.1 [except.throw].

David Abrahams (February 2004):
It appears, looking at core 291, that there may be a need to tighten
up 8.5.3 [dcl.init.ref]/5.

Please see the attached example file, which demonstrates "move
semantics" in C++98. Many compilers fail to compile test 10 because
of the way 8.5.3/5 is interpreted. My problem with that
interpretation is that test 20:

typedef X const XC;
sink2(XC(X()));

does compile. In other words, it *is* possible to construct the const
temporary from the rvalue. IMO, that is the proper test.

8.5.3/5 doesn't demand that a "copy constructor" is used to copy the
temporary, only that a constructor is used "to copy the temporary".
I hope that when the language is tightened up to specify direct (or
copy initialization), that it also unambiguously allows the enclosed
test to compile. Not only is it, I believe, within the scope of
reasonable interpretation of the current standard, but it's an
incredibly important piece of functionality for library writers and
users alike.

Change paragraph 5, second bullet,
first sub-bullet, second sub-sub-bullet as follows:

A temporary of type "cv1T2" [sic] is created, and a
constructor is called to copy the entire rvalue object into the temporaryvia copy-initialization from the entire rvalue object.
The reference is bound to the temporary or to a sub-object
within the temporary.

The text immediately following that is changed as follows:

The constructor that would be used to make the copy shall be
callable whether or not the copy is actually done.The constructor and any conversion function that would be used in the
initialization shall be callable whether or not the temporary is
actually created.

Note, however, that the way the core working group is leaning
on issue 391 (i.e., requiring direct
binding) would make this change unnecessary.

391.
Require direct binding of short-lived references to rvalues

After some email exchanges with Rani Sharoni, I've come up
with the following proposal to allow reference binding to
non-copyable rvalues in some cases. Rationale and some
background appear afterwards.

---- proposal ----

Replace the section of 8.5.3 [dcl.init.ref] paragraph 5
that begins "If the initializer expression is an rvalue" with the
following:

If the initializer expression is an rvalue, with T2 a
class type, and ``cv1 T1'' is reference-compatible with
``cv2 T2,'' the reference is bound as follows:

If the lifetime of the reference does not extend
beyond the end of the full expression containing the
initializer expression, the reference is bound to
the object represented by the rvalue (see 3.10 [basic.lval]) or
to a sub-object within that object.

otherwise, the reference is bound in one of the
following ways (the choice is implementation-defined):

[... continues as before - the original wording applies
unchanged to longer-lived references]

---- rationale ----

The intention of the current wording is to provide the
implementation freedom to construct an rvalue of class
type at an arbitrary location and copy it zero or more
times before binding any reference to it.

The standard allows code to call a member function on an
rvalue of class type (in 5.2.5 [expr.ref], I guess).
This means that
the implementation can be forced to bind the reference
directly, with no freedom to create any temporary
copies. e.g.

Forcing a direct binding in this way is possible wherever
the lifetime of the reference does not extend beyond the
containing full expression, since the reference returned
by the member function remains valid for this long.

As demonstrated above, existing implementations must
already be capable of constructing an rvalue of class
type in the "right" place the first time. Some compilers
already silently allow the direct binding of references
to non-copyable rvalues.

The change will not break any portable user code. It
would break any platform-specific user code that relies
on copies being performed by the particular
implementation.

---- background ----

The proposal is based on a recent discussion in this
group. I originally wanted to leave the implementation free
to copy the rvalue if there was a callable copy constructor,
and only have to bind directly if none was callable.
Unfortunately, a traditional compiler can't always tell
whether a function is callable or not, e.g. if the copy
constructor is declared but not defined. Rani pointed this
out in an example, and suggested that maybe trivial copy
constructors should still be allowed (by extension, maybe
wherever the compiler can determine callability). I've gone
with this version because it's simpler, and I also figure
the "as if" rule gives the compiler some freedom with POD
types anyway.

Notes from April 2003 meeting:

We agreed generally with the proposal. We were unsure about the
need for the restriction regarding long-lived references.
We will check with the proposer about that.

Jason Merrill points out that the test case in
issue 86 may be a case where we
do not want to require direct binding.

Further information from Rani Sharoni (April 2003):

I wasn't aware about the latest suggestion of Raoul as it appears in
core issue 391. In our discussions we tried to formulate a different
proposal.

The rational, as we understood, behind the implementation freedom to
make an extra copying (8.5.3/5/2/12) of the rvalue is to allow return
values in registers which on some architectures are not addressable.
The example that Raoul and I presented shows that this implementation
freedom is not always possible since we can "force" the rvalue to be
addressable using additional member function (by_ref). The example
only works for short lived rvalues and this is probably why Raoul
narrow the suggestion.

I had different rational which was related to the implementation of
conditional operator in VC. It seems that when conditional operator is
involved VC does use an extra copying when the lifetime of the
temporary is extended:

I don't know what the consideration behind the VC implementation was
(I saw open bug on this issue) but it convinced me to narrow the
suggestion.

IMHO such limitation seems to be too strict because it might limit the
optimizer since returning class rvalues in registers might be useful
(although I'm not aware about any implementation that actually does
it). My suggestion was to forbid the extra copying if the ctor is not
viable (e.g. A::A(A&) ). In this case the implementation "freedom"
doesn't exist (since the code might not compile) and only limits the
programmer freedom (e.g. Move Constructors -
http://www.cuj.com/experts/2102/alexandr.htm).

Core issue 291 is strongly related to
the above issue and I personally
prefer to see it resolved first. It seems that VC already supports the
resolution I prefer.

Notes from October 2003 meeting:

We ended up feeling that this is just one of a number of cases
of optimizations that are widely done by compilers
and allowed but not required by the standard. We don't see any
strong reason to require compilers to do this particular
optimization.

Notes from the March 2004 meeting:

After discussing issue 450, we
found ourselves reconsidering this, and we are now inclined to
make a change to require the direct binding in all cases,
with no restriction on long-lived references. Note that such
a change would eliminate the need for a change for
issue 291.

If the initializer expression is an rvalue, with T2 a class type,
and "cv1T1" is reference-compatible with
"cv2T2", the reference is bound to the
object represented by the rvalue (see 3.10 [basic.lval]) or to a sub-object within that object.in one of the following ways (the choice is
implementation-defined):

The reference is bound to the object represented by the
rvalue (see 3.10 [basic.lval]) or to a sub-object
within that object.

A temporary of type "cv1T2" [sic] is created, and a
constructor is called to copy the entire rvalue object into the
temporary. The reference is bound to the temporary or to a
sub-object within the temporary.

The constructor that would be used to make the copy shall be
callable whether or not the copy is actually done.
[Example:

struct A { };
struct B : public A { } b;
extern B f();
const A& rca = f (); // BoundEither bound to the A sub-object of the B rvalue,
// or the entire B object is copied and the reference
// is bound to the A sub-object of the copy

When you run this through 8.5.3 [dcl.init.ref], you sort of end up
falling off the end of the standard's description of reference
binding. The standard says in the final bullet of paragraph 5
that an array temporary should be created and copy-initialized
from the rvalue array, which seems implausible.

I'm not sure what the right answer is. I think I'd be happy with
allowing the binding in this case. We would have to introduce
a special case like the one for class rvalues.

Notes from the March 2004 meeting:

g++ and EDG give an error. Microsoft (8.0 beta) and Sun accept
the example. Our preference is to allow the direct binding (no copy).
See the similar issue with class rvalues in
issue 391.

If the initializer expression is an rvalue, with T2 an
array type, and “cv1T1” is
reference-compatible with “cv2T2”,
the reference is bound to the object represented by the rvalue
(see 3.10 [basic.lval]).

Change 3.10 [basic.lval] paragraph 2 as
follows:

An lvalue refers to an object or function. Some rvalue
expressions — those of (possibly cv-qualified) class
or array typeor cv-qualified class type —
also refer to objects.

175.
Class name injection and base name access

With class name injection, when a base class name is used in a derived
class, the name found is the injected name in the base class, not the
name of the class in the scope containing the base class.
Consequently, if the base class name is not accessible (e.g., because
is is in a private base class), the base class name cannot be used
unless a qualified name is used to name the class in the class or
namespace of which it is a member.

Without class name injection the following example is valid. With
class name injection, A is inaccessible in class C.

At the least, the standard should be more explicit that this is, in
fact, ill-formed.

(See paper J16/99-0010 = WG21 N1187.)

Proposed resolution (04/01):

Add to the end of 11.1 [class.access.spec] paragraph 3:

[Note: In a derived class, the lookup of a base class name
will find the injected-class-name instead of the name of the base
class in the scope in which it was declared. The
injected-class-name might be less accessible than the name of the
base class in the scope in which it was declared.] [Example:

273.
POD classes and operator&()

I think that the definition of a POD class in the current version
of the Standard is overly permissive in that it allows for POD classes
for which a user-defined operator function operator& may
be defined. Given that the idea behind POD classes was to achieve
compatibility with C structs and unions, this makes 'Plain old'
structs and unions behave not quite as one would expect them to.

In the C language, if x and y are variables of
struct or union type S that has a member m, the
following expression are allowed: &x, x.m, x
= y. While the C++ standard guarantees that if x and
y are objects of a POD class type S, the expressions
x.m, x = y will have the same effect as they would
in C, it is still possible for the expression &x to be
interpreted differently, subject to the programmer supplying an
appropriate version of a user-defined operator function
operator& either as a member function or as a non-member
function.

For any complete POD object type T, whether or not the object
holds a valid value of type T, the underlying bytes
(1.7 [intro.memory]) making up the object can be copied into
an array of char or unsigned char [footnote:
By using, for example, the library functions (17.6.1.2 [headers]) memcpy or memmove]. 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:

#define N sizeof(T)
char buf[N];
T obj; // obj initialized to its original value
memcpy(buf, &obj, N);
// between these two calls to memcpy,
// obj might be modified
memcpy(&obj, buf, N);
// at this point, each subobject of obj of scalar type
// holds its original value

—end example]

Now, supposing that the complete POD object type T in the
example above is POD_bomb, and we cannot any more count on
the assertions made in the comments to the example. Given a standard
conforming implementation, the code will not even compile. And I see
no legal way of copying the contents of an object of a complete object
type POD_bomb into an array of char or unsigned
char with memcpy or memmove without making use
of the unary & operator. Except, of course, by means of
an ugly construct like:

The fact that the definition of a POD class allows for POD classes
for which a user-defined operator& is defined, may also
present major obstacles to implementers of the offsetof macro from
<cstddef>

18.2 [support.types] paragraph 5 says:

The macro offsetof accepts a restricted set of type arguments
in this International Standard. type shall be a POD structure
or a POD union (clause 9 [class]). The result of
applying the offsetof macro to a field that is a static data
member or a function is undefined."

A consensus was forming around the idea of disallowing
operator& in POD classes when it was noticed that it is
permitted to declare global-scope operator& functions,
which cause the same problems. After more discussion, it was
decided that such functions should not be prohibited in POD classes,
and implementors should simply be required to "get the right answer"
in constructs such as offsetof and va_start that
are conventionally implemented using macros that use the "&"
operator. It was noted that one can cast the original operand to
char & to de-type it, after which one can use the
built-in "&" safely.

Proposed resolution:

Add a footnote in 18.2 [support.types] paragraph 5:

[Footnote: Note that offsetof is required to
work as specified even if unary operator& is
overloaded for any of the types involved.]

Add a footnote in 18.10 [support.runtime] paragraph 3:

[Footnote: Note that va_start is required to
work as specified even if unary operator& is
overloaded for the type of parmN.]

284.
qualified-ids in class declarations

Although 8.3 [dcl.meaning] requires that a declaration of
a qualified-id refer to a member of the specified namespace or
class and that the member not have been introduced by a
using-declaration, it applies only to names declared in a
declarator. It is not clear whether there is existing wording
enforcing the same restriction for qualified-ids in
class-specifiers and elaborated-type-specifiers or
whether additional wording is required. Once such wording is
found/created, the proposed resolution of
issue 275 must be modified accordingly.

Notes from 10/01 meeting:

The sentiment was that this should be required on class definitions, but
not on elaborated type specifiers in general (which are references, not
declarations). We should also make sure we consider explicit instantiations,
explicit specializations, and friend declarations.

Proposed resolution (10/01):

Add after the end of 9.1 [class.name] paragraph 3:

When a nested-name-specifier is specified in a
class-head or in an
elaborated-type-specifier, the resulting qualified name
shall refer to a previously declared member of the class or namespace to
which the nested-name-specifier refers, and
the member shall not have been introduced by a
using-declaration in the scope of the class or namespace
nominated by the nested-name-specifier.

327.
Use of "structure" without definition

In 9 [class] paragraph 4, the first sentence says
"A structure is a class
definition defined with the class-keystruct".
As far as I know,
there is no such thing as a structure in C++; it certainly isn't
listed as one of the possible compound types in 3.9.2 [basic.compound].
And defining structures opens the question of whether a forward
declaration is a structure or not. The parallel here with union
(which follows immediately) suggests that structures and classes are
really different things, since the same wording is used, and classes
and unions do have some real differences, which manifest themselves
outside of the definition. It also suggests that since one can't
forward declare union with class and vice versa, the same should
hold for struct and class -- I believe that the intent was that one
could use struct and class interchangeably in forward declaration.

Suggested resolution:

I suggest something like the following:

If a class is defined with the class-keyclass, its members and
base classes are private by default. If a class is defined with
the class-keystruct,
its members and base classes are public by
default. If a class is defined with the class-keyunion, its
members are public by default, and it holds only one data member
at a time. Such classes are called unions, and obey a number of
additional restrictions, see 9.5 [class.union].

379.
Change "class declaration" to "class definition"

The ARM used the term "class declaration" to refer to what
would usually be termed the definition of the class. The standard
now often uses "class definition", but there are some surviving uses
of "class declaration" with the old meaning. They should be found
and changed.

Proposed resolution (April 2003):

Replace in 3.1 [basic.def] paragraph 2

A declaration is a definition unless it declares a function
without specifying the function's body
(8.4 [dcl.fct.def]), it contains the
extern specifier (7.1.1 [dcl.stc]) or
a linkage-specification
[Footnote: Appearing inside the braced-enclosed
declaration-seq in a linkage-specification does not
affect whether a declaration is a definition. --- end
footnote]
(7.5 [dcl.link]) and neither an
initializer nor a function-body, it declares a static
data member in a class declarationdefinition
(9.4 [class.static]), it is a class name
declaration (9.1 [class.name]), or it is
a typedef declaration
(7.1.3 [dcl.typedef]), a
using-declaration
(7.3.3 [namespace.udecl]), or a
using-directive
(7.3.4 [namespace.udir]).

Replace in 7.1.2 [dcl.fct.spec] paragraphs 5 and 6

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

The explicit specifier shall be used only in declarations of
constructors within a class declarationdefinition; see
12.3.1 [class.conv.ctor].

Replace in 7.1.3 [dcl.typedef] paragraph 4

A
typedef-name
that names a class is a
class-name
(9.1 [class.name]).
If a typedef-name is used following the class-key
in an elaborated-type-specifier
(7.1.6.3 [dcl.type.elab]) or in the
class-head
of a class declarationdefinition
(9 [class]),
or is used as the identifier in the declarator for a
constructor or destructor declaration
(12.1 [class.ctor],
12.4 [class.dtor]), the program is ill-formed.

Replace in 7.3.1.2 [namespace.memdef] paragraph 3

The name of the friend is not found by simple name lookup until a
matching declaration is provided in that namespace scope (either
before or after the class declarationdefinition granting friendship).

Replace in 8.3.2 [dcl.ref] paragraph 4

There shall be no references to references, no arrays of references,
and no pointers to references. The declaration of a reference shall
contain an initializer
(8.5.3 [dcl.init.ref]) except when
the declaration contains an explicit extern specifier
(7.1.1 [dcl.stc]), is a class member
(9.2 [class.mem]) declaration within a
class declarationdefinition, or is the
declaration of a parameter or a return type
(8.3.5 [dcl.fct]); see
3.1 [basic.def].

Replace in 8.5.3 [dcl.init.ref] paragraph 3

The initializer can be omitted for a reference only in a parameter
declaration (8.3.5 [dcl.fct]), in the
declaration of a function return type, in the declaration of a class
member within its class declarationdefinition
(9.2 [class.mem]), and where the
extern specifier is explicitly used.

Replace in 9.1 [class.name] paragraph 2

A class definitiondeclaration introduces the
class name into the scope where it is defineddeclared and hides any class, object, function, or other
declaration of that name in an enclosing scope
(3.3 [basic.scope]). If a class name
is declared in a scope where an object, function, or enumerator of the
same name is also declared, then when both declarations are in scope,
the class can be referred to only using an
elaborated-type-specifier
(3.4.4 [basic.lookup.elab]).

Replace in 9.4 [class.static] paragraph 4

Static members obey the usual class member access rules (clause
11 [class.access]). When used
in the declaration of a class member, the static specifier
shall only be used in the member declarations that appear within the
member-specification of the class declarationdefinition.

Replace in 9.7 [class.nest] paragraph 1

A class can be defineddeclared within another
class. A class defineddeclared within
another is called a nested class. The name of a nested class
is local to its enclosing class. The nested class is in the scope of
its enclosing class. Except by using explicit pointers, references,
and object names, declarations in a nested class can use only type
names, static members, and enumerators from the enclosing class.

Replace in 9.8 [class.local] paragraph 1

A class can be defineddeclared within a
function definition; such a class is called a local class. The
name of a local class is local to its enclosing scope. The local
class is in the scope of the enclosing scope, and has the same access
to names outside the function as does the enclosing function.
Declarations in a local class can use only type names, static
variables, extern variables and functions, and enumerators
from the enclosing scope.

Replace in 10 [class.derived] paragraph 1

... The class-name in a base-specifier shall not be an
incompletely defined class (clause 9 [class]);
this class is called a
directbaseclass for the class being
declareddefined. During the lookup for a
base class name, non-type names are ignored
(3.3.10 [basic.scope.hiding]).
If the name found is not a class-name, the program is ill-formed.
A class B is a base class of a class D if it is a
direct base class of D or a direct base class of one of
D's base classes. A class is an indirect base class
of another if it is a base class but not a direct base class. A class
is said to be (directly or indirectly) derived from its (direct
or indirect) base classes. [Note: See clause
11 [class.access]
for the meaning of access-specifier.] Unless
redefinedredeclared in the
derived class, members of a base class are also considered to be
members of the derived class. The base class members are said to be
inherited by the derived class. Inherited members can be
referred to in expressions in the same manner as other members of the
derived class, unless their names are hidden or ambiguous
(10.2 [class.member.lookup]).
[Note: the scope resolution operator ::
(5.1.1 [expr.prim.general])
can be used to refer to a direct or indirect base member explicitly.
This allows access to a name that has been redefinedredeclared in the derived class. A derived class can itself
serve as a base class subject to access control; see
11.2 [class.access.base].
A pointer to a derived class can be implicitly converted to a pointer
to an accessible unambiguous base class
(4.10 [conv.ptr]).
An lvalue of a derived class type can be bound to a reference to an
accessible unambiguous base class
(8.5.3 [dcl.init.ref]).]

for an object c of class type C, a single subobject
of type V is shared by every base subobject of c
that is declared to havehas a
virtual base class of type V.

Replace in the example in 10.2 [class.member.lookup]
paragraph 6 (the whole paragraph was turned into a note by the
resolution of core issue 39)

The names defineddeclared in V and
the left hand instance of W are hidden by those in
B, but the names defineddeclared in
the right hand instance of W are not hidden at all.

Replace in 10.4 [class.abstract] paragraph 2

... A virtual function is specified pure by using a
pure-specifier (9.2 [class.mem])
in the function declaration in the class declarationdefinition. ...

Replace in the footnote at the end of 11.2 [class.access.base]
paragraph 1

[Footnote: As specified previously in clause
11 [class.access], private members of
a base class remain inaccessible even to derived classes unless
friend declarations within the base class
declarationdefinition are used to grant access
explicitly.]

Replace in _N3225_.11.3 [class.access.dcl] paragraph 1

The access of a member of a base class can be changed in the derived
class by mentioning its qualified-id in the derived class
declarationdefinition. Such mention is
called an accessdeclaration. ...

Replace in the example in 13.4 [over.over] paragraph 5

The initialization of pfe is ill-formed because no
f() with type int(...) has been
defineddeclared, and not because of any
ambiguity.

Replace in C.1.6 [diff.dcl] paragraph 1

Rationale: Storage class specifiers don't have any meaning when
associated with a type. In C++, class members can be
defineddeclared with the static
storage class specifier. Allowing storage class specifiers on type
declarations could render the code confusing for users.

Replace in C.1.8 [diff.class] paragraph 3

In C++, a typedef name may not be redefinedredeclared in a class
declarationdefinition after being used in the
declarationthat definition

383.
Is a class with a declared but not defined destructor a POD?

The standard (9 [class] par. 4) says that
"A POD-struct is an aggregate class
that has no non-static data members of type non-POD-struct,
non-POD-union (or array of such types) or reference, and has no
user-defined copy assignment operator and no user-defined destructor."

Note that it says 'user-defined', not 'user-declared'. Is it the
intent that if e.g. a copy assignment operator is declared but not
defined, this does not (per se) prevent the class to be a POD-struct?

Proposed resolution (April 2003):

Replace in 9 [class] paragraph 4

A POD-struct is an aggregate class that has no non-static data
members of type non-POD-struct, non-POD-union (or array of such types)
or reference, and has no user-defineddeclared
copy assignment operator and no user-defineddeclared destructor. Similarly, a POD-union is an
aggregate union that has no non-static data members of type
non-POD-struct, non-POD-union (or array of such types) or reference,
and has no user-defineddeclared copy
assignment operator and no user-defineddeclared destructor.

Drafting note: The changes are shown relative to TC1, incorporating
the changes from the resolution of
core issue 148.

413.
Definition of "empty class"

The proposal says that value is true if "T is an empty class (10)".
Clause 10 doesn't define an empty class, although it has a note that
says a base class may "be of zero size (clause 9)" 9/3 says "Complete
objects and member subobjects of class type shall have nonzero size."
This has a footnote, which says "Base class subobjects are not so
constrained."

The standard uses the term "empty class" in two places
(8.5.1 [dcl.init.aggr]), but neither of
those places defines it. It's also listed in the index, which refers to
the page that opens clause 9, i.e. the nonzero size stuff cited above.

So, what's the definition of "empty class" that determines whether the
predicate is_empty is true?

The one place where it's used is
8.5.1 [dcl.init.aggr] paragraph 8, which says (roughly paraphrased)
that an aggregate initializer for an empty class must be "{}", and when
such an initializer is used for an aggregate that is not an empty class the
members are default-initialized. In this context it's pretty clear what's
meant. In the type traits proposal it's not as clear, and it was probably
intended to have a different meaning. The boost implementation, after it
eliminates non-class types, determines whether the trait is true by
comparing the size of a class derived from T to the size of an
otherwise-identical class that is not derived from T.

Howard Hinnant:is_empty was created to find out whether a type could be derived from
and have the empty base class optimization successfully applied. It
was created in part to support compressed_pair which attempts to
optimize away the space for one of its members in an attempt to reduce
spatial overhead. An example use is:

Here the compare function is optimized away via the empty base
optimization if Compare turns out to be an "empty" class. If Compare
turns out to be a non-empty class, or a function pointer, the space is
not optimized away. is_empty is key to making this work.

Clark Nelson:
I've been looking at issue 413, and I've reached the conclusion that
there are two different kinds of empty class. A class containing only
one or more anonymous bit-field members is empty for purposes of
aggregate initialization, but not (necessarily) empty for purposes of
empty base-class optimization.

Of course we need to add a definition of emptiness for purposes of
aggregate initialization. Beyond that, there are a couple of questions:

Should the definition of emptiness used by the is_empty predicate be
defined in a language clause or a library clause?

Do we need to open a new core issue pointing out the fact that the
section on aggregate initialization does not currently say that unnamed
bit-fields are skipped?

Notes from the October, 2005 meeting:

There are only two places in the Standard where the phrase
“empty class” appears, both in 8.5.1 [dcl.init.aggr] paragraph 8. Because it is not clear whether the
definition of “empty for initialization purposes” is
suitable for use in defining the is_empty predicate, it would
be better just to avoid using the phrase in the language clauses. The
requirements of 8.5.1 [dcl.init.aggr] paragraph 8 appear to be
redundant; paragraph 6 says that an initializer-list must have
no more initializers than the number of elements to initialize, so an
empty class already requires an empty initializer-list, and
using an empty initializer-list with a non-empty class is
covered adequately by paragraph 7's description of the handling of an
initializer-list with fewer initializers than the
number of members to initialize.

Here, the second initializer 2 initializes a.j and not the
static data member A::s, and the third initializer 3
initializes a.k and not the padding before it.
—end example]

Delete 8.5.1 [dcl.init.aggr] paragraph 8:

An initializer for an aggregate member that is an empty
class shall have the form of an empty initializer-list{}. [Example:

struct S { };
struct A {
S s;
int i;
} a = { { } , 3 };

—end example] An empty initializer-list can be used to
initialize any aggregate. If the aggregate is not an empty class, then
each member of the aggregate shall be initialized with a value of the
form T() (5.2.3 [expr.type.conv]), where T
represents the type of the uninitialized member.

Deleting 8.5.1 [dcl.init.aggr] paragraph 8 altogether may
not be a good idea. It would appear that, in its absence, the
initializer elision rules of paragraph 11 would allow the initializer
for a in the preceding example to be written { 3 }
(because the empty-class member s would consume no
initializers from the list).

Proposed resolution (October, 2006):

(Drafting note: this resolution also cleans up incorrect
references to syntactic non-terminals in the nearby paragraphs.)

Change 8.5.1 [dcl.init.aggr] paragraph 4 as indicated:

An array of unknown size initialized with a brace-enclosed
initializer-list containing ninitializersinitializer-clauses, where n shall be greater
than zero... An empty initializer list {} shall not be used as the
initializerinitializer-clause for an array of
unknown bound.

Here, the second initializer 2 initializes a.j
and not the static data member A::s, and the third
initializer 3 initializes a.k and not the anonymous
bit field before it. —end example]

Change 8.5.1 [dcl.init.aggr] paragraph 6 as indicated:

An initializer-list is ill-formed if the number of
initializersinitializer-clauses
exceeds the number of members...

Change 8.5.1 [dcl.init.aggr] paragraph 7 as indicated:

If there are fewer initializersinitializer-clauses in the list than there are members...

Replace 8.5.1 [dcl.init.aggr] paragraph 8:

An initializer for an aggregate member that is an empty
class shall have the form of an empty initializer-list{}. [Example:

struct S { };
struct A {
S s;
int i;
} a = { { } , 3 };

—end example] An empty initializer-list can be used to
initialize any aggregate. If the aggregate is not an empty class, then
each member of the aggregate shall be initialized with a value of the
form T() (5.2.3 [expr.type.conv]), where T
represents the type of the uninitialized member.

with:

If an aggregate class C contains a subaggregate
member m that has no members for purposes of aggregate
initialization, the initializer-clause for m shall not
be omitted from an initializer-list for an object of type
C unless the initializer-clauses for all members
of C following m are also omitted. [Example:

When initializing a multi-dimensional array, the initializersinitializer-clauses initialize the elements...

Change 8.5.1 [dcl.init.aggr] paragraph 11 as indicated:

Braces can be elided in an initializer-list as follows. If the
initializer-list begins with a left brace, then the succeeding
comma-separated list of initializersinitializer-clauses initializes the members of a
subaggregate; it is erroneous for there to be more initializersinitializer-clauses than members. If, however,
the initializer-list for a subaggregate does not begin with a
left brace, then only enough initializersinitializer-clauses from the list are taken to
initialize the members of the subaggregate; any
remaining initializersinitializer-clauses
are left to initialize the next member of the aggregate of which the
current subaggregate is a member. [Example:...

Change 8.5.1 [dcl.init.aggr] paragraph 12 as indicated:

All implicit type conversions (clause 4 [conv]) are
considered when initializing the aggregate member with an initializer
from an initializer-listassignment-expression. If
the initializerassignment-expression can
initialize a member, the member is initialized. Otherwise, if the
member is itself a non-empty subaggregate, brace elision is
assumed and the initializerassignment-expression is considered for the
initialization of the first member of the
subaggregate. [Note: As specified above, brace elision
cannot apply to subaggregates with no members for purposes of
aggregate initialization; an initializer-clause for the entire
subobject is required. —end note]
[Example:... Braces are elided around
the initializerinitializer-clause for
b.a1.i...

Change 8.5.1 [dcl.init.aggr] paragraph 15 as indicated:

When a union is initialized with a brace-enclosed initializer, the
braces shall only contain an initializerinitializer-clause for the first member of the
union...

Change 8.5.1 [dcl.init.aggr] paragraph 16 as indicated:

[Note:asAs described above, the braces around
the initializerinitializer-clause for a union
member can be omitted if the union is a member of another
aggregate. —end note]

There are several problems with the terms defined in
9 [class] paragraph 4:

A structure is a class defined with
the class-keystruct; its members and base classes
(clause 10 [class.derived]) are public by default (clause
11 [class.access]). A union is a class defined with the
class-keyunion; its members are public by default and
it holds only one data member at a time (9.5 [class.union]). [Note: aggregates of class type are described
in 8.5.1 [dcl.init.aggr]. —end note]
A POD-struct is an aggregate class that has no non-static data
members of type non-POD-struct, non-POD-union (or array of such types)
or reference, and has no user-declared copy assignment operator and no
user-declared destructor. Similarly, a POD-union is an
aggregate union that has no non-static data members of type
non-POD-struct, non-POD-union (or array of such types) or reference,
and has no user-declared copy assignment operator and no user-declared
destructor. A POD class is a class that is either a POD-struct
or a POD-union.

Although the term structure is defined here, it is
used only infrequently throughout the Standard, often apparently
inadvertently and consequently incorrectly:

5.2.5 [expr.ref] paragraph 4: the use is in a
note and is arguably correct and helpful.

9.2 [class.mem] paragraph 11: the term is used
(three times) in an example. There appears to be no reason to use
it instead of “class,” but its use is not
problematic.

17.3 [definitions] “iostream class templates:”
the traits argument
to the iostream class templates is (presumably unintentionally)
constrained to be a structure, i.e., to use the struct
keyword and not the class keyword in its definition.

B [implimits] paragraph 2: the minimum number of
declarator operators is given for structures and unions but not
for classes defined using the class keyword.

B [implimits] paragraph 2: class, structure,
and union are used as disjoint terms in describing nesting
levels. (The nonexistent nonterminal struct-declaration-list
is used, as well.)

There does not appear to be a reason for defining the term
structure. The one reference where it is arguably useful,
in the note in 5.2.5 [expr.ref], could be rewritten
as something like, “'class objects' may be defined using the
class, struct, or unionclass-keys; see clause 9 [class].”

Based on its usage later in the paragraph and elsewhere,
“POD-struct” appears to be intended to exclude unions.
However, the definition of “aggregate class” in
8.5.1 [dcl.init.aggr] paragraph 1 includes unions.
Furthermore, the name itself is confusing, leading to the question of
whether it was intended that only classes defined
using struct could be POD-structs or
if class-classes are included. The definition should
probably be rewritten as, “A POD-struct is an aggregate
class defined with the class-keystruct or
the class-keyclass that has no...

In most references outside clause 9 [class],
POD-struct and POD-union are mentioned together and treated
identically. These references should be changed to refer to the
unified term, “POD class.”

Noted in passing: 18.2 [support.types] paragraph 4
refers to the undefined terms “POD structure” and
(unhyphenated) “POD union;” the pair should be replaced
by a single reference to “POD class.”

Proposed resolution (April, 2006):

Change 9 [class] paragraph 4 as indicated:

A structure is a class defined with
the class-keystruct; its members and base classes
(clause 10 [class.derived]) are public by default (clause
11 [class.access]). A union is a class defined with the
class-keyunion; its members are public by default
and it holds only one data member at a time (9.5 [class.union]). [Note: aggregates of class type are described
in 8.5.1 [dcl.init.aggr]. —end note]
A POD-struct is an aggregate class that has no non-static
data members of type non-POD-struct, non-POD-union (or array of such
types) or reference, and has no user-declared copy assignment operator
and no user-declared destructor. Similarly, a POD-union is an
aggregate union that has no non-static data members of type
non-POD-struct, non-POD-union (or array of such types) or reference,
and has no user-declared copy assignment operator and no user-declared
destructor. A POD class is a class that is either a POD-struct
or a POD-union.A POD class is an aggregate class that
has no non-static data members of non-POD type (or array of such a
type) or reference, and has no user-declared copy assignment operator
and no user-declared destructor. A POD-struct is a POD class
defined with the class-keystruct or
the class-keyclass. A POD-union is a POD class
defined with the class-keyunion.

Change 11.2 [class.access.base] paragraph 2 as indicated:

In the absence of an access-specifier for a base
class, public is assumed when the derived class is
declareddefined with
the class-keystruct and private is
assumed when the class is declareddefined with the
class-keyclass. [Example:...

568.
Definition of POD is too strict

[Voted into the WP at the July, 2007 meeting as part of paper
J16/07-0202 = WG21 N2342.]

A POD struct (9 [class] paragraph 4) is “an
aggregate class that has no non-static data members of type
non-POD-struct, non-POD-union (or array of such types), or reference,
and that has no user-defined copy assignment operator and no
user-defined destructor.” Meanwhile, an aggregate class
(8.5.1 [dcl.init.aggr] paragraph 1) must have “no
user-declared constructors, no private or protecte non-static data
members, no base classes, and no virtual functions.”

This is too strict. The whole reason we define the notion of POD is
for the layout compatibility guarantees in 9.2 [class.mem]
paragraphs 14-17 and the byte-for-byte copying guarantees of
3.9 [basic.types] paragraph 2. None of those guarantees
should be affected by the presence of ordinary constructors, any more
than they're affected by the presence of any other member
function. It’s silly for the standard to make layout and memcpy
guarantees for this class:

struct A {
int n;
};

but not for this one:

struct B {
int n;
B(n_) : n(n_) { }
};

With either A or B, it ought to be possible to
save an array of those objects to disk with a single call to
Unix’s write(2) system call or the equivalent. At present the
standard says that it’s legal for A but not B,
and there isn’t any good reason for that distinction.

Suggested resolution:

The following doesn’t fix all problems (in particular it
still doesn’t let us treat pair<int, int> as a
POD), but at least it goes a long way toward fixing the problem: in
8.5.1 [dcl.init.aggr] paragraph 1, change “no
user-declared constructors” to “no nontrivial default
constructor and no user-declared copy constructor.”

(Yes, I’m aware that this proposed change would also allow
brace initialization for some types that don't currently allow it. I
consider this to be a feature, not a bug.)

Mike Miller: I agree that something needs to be done about
“POD,” but I’m not sure that this is it. My own
take is that “POD” is used for too many different things
— things that are related but not identical — and the
concept should be split. The current definition is useful, as is, for
issues regarding initialization and lifetime. For example, I
wouldn’t want to relax the prohibition of jumping over a
constructor call in 6.7 [stmt.dcl] (which is currently
phrased in terms of POD types). On the other hand, I agree that the
presence of a user-declared constructor says nothing about layout and
bitwise copying. This needs (IMHO) a non-trivial amount of further
study to determine how many categories we need (instead of just POD
versus non-POD), which guarantees and prohibitions go with which
category, the interaction of “memcpy initialization” (for
want of a better term) with object lifetime, etc.

417.
Using derived-class qualified name in out-of-class nested class definition

We had a user complain that our compiler was allowing the
following code:

struct B {
struct S;
};
struct D : B { };
struct D::S {
};

We took one look at the code and made the reasonable (I would claim)
assumption that this was
indeed a bug in our compiler. Especially as we had just fixed a very
similar issue with the
definition of static data members.

Imagine our surprise when code like this showed up in Boost and that
every other compiler we tested accepts this code. So is this
indeed legal (it seems like
it must be) and if so is there any justification for this beyond
3.4.3.1 [class.qual]?

John Spicer:
The equivalent case for a member function is covered by the declarator
rules in 8.3 [dcl.meaning] paragraph 1. The committee has
previously run into cases where a restriction should apply to both
classes and non-classes, but fails to do so because there is no
equivalent of 8.3 [dcl.meaning] paragraph 1 for classes.

Given that, by the letter of the standard, I would say that this
case is allowed.

Add the following as a new paragraph immediately following
3.3.2 [basic.scope.pdecl] paragraph 2:

The point of declaration for a class first declared by a
class-specifier is
immediately after the identifier
or template-id (if any) in its class-head
(Clause 9 [class]).
The point of declaration for an enumeration is immediately after
the identifier (if any) in its enum-specifier
(7.2 [dcl.enum]).

Change point 1 of 3.3.7 [basic.scope.class] paragraph 1 to read:

The potential scope of a name declared in a class consists not only of the
declarative region following the name's
declaratorpoint of declaration, but also
of all function bodies, default arguments, and constructor
ctor-initializers in that
class (including such things in nested classes).

[Note that the preceding change duplicates one of the changes
in the proposed resolution of issue 432.]

Change 14.7.2 [temp.explicit] paragraph 2 to read:

If the explicit instantiation is for a member function, a member
class or a static
data member of a class template specialization, the name of
the class template
specialization in the qualified-id for the member declaratorname shall be a template-id.

Add the following as paragraph 5 of Clause 9 [class]:

If a class-head contains a nested-name-specifier,
the class-specifier shall refer to a
class that was previously declared directly in the class or namespace
to which the nested-name-specifier refers (i.e., neither
inherited nor introduced by a using-declaration),
and the class-specifier shall appear in a namespace enclosing the
previous declaration.

When a nested-name-specifier is specified in a
class-head or in an
elaborated-type-specifier, the resulting qualified name
shall refer to a previously declared member of the class or namespace to
which the nested-name-specifier refers, and
the member shall not have been introduced by a
using-declaration in the scope of the class or namespace
nominated by the nested-name-specifier.

328.
Missing requirement that class member types be complete

Is it legal to use an incomplete type (3.9 [basic.types]
paragraph 6) as a
class member, if no object of such class is ever created ?

And as a class template member, even if the template is instantiated,
but no object of the instantiated class is created?

The consensus seems to be NO, but no wording was found in the standard
which explicitly disallows it.

The problem seems to be that most of the restrictions on incomplete types
are on their use in objects, but class members are not objects.

A possible resolution, if this is considered a defect, is to add to
3.2 [basic.def.odr] paragraph 4, (situations when T must be complete),
the use of T as a member of a class or instantiated class template.

The thread on comp.std.c++ which brought up the issue was
"Compiler differences: which is correct?", started 2001 11 30.
<3c07c8fb$0$8507$ed9e5944@reading.news.pipex.net>

Proposed Resolution (April 2002, revised April 2003):

Change the first bullet of the note in 3.2 [basic.def.odr]
paragraph 4 and add two new bullets following it, as follows:

an object of type T is defined
(3.1 [basic.def], 5.3.4 [expr.new]), or

a non-static class data member of type T is declared
(9.2 [class.mem]), or

T is used as the object type or array element type
in a new-expression (5.3.4 [expr.new]), or

Replace 9.2 [class.mem] paragraph 8 by:

Non-static (9.4 [class.static]) data members shall
not have incomplete types.
In particular, a class C shall not contain a non-static
member of class C, but it can contain a pointer or reference to
an object of class C.

See also 3.9 [basic.types] paragraph 6, which is relevant
but not changed by the Proposed Resolution.

437.
Is type of class allowed in member function exception specification?

The compiler is complaining that Foo is an incomplete type, and can't be
used in the exception specification.

My reading of the standard [basic.types] is inconclusive. Although it
does state that the class declaration is considered complete when the
closing brace is read, I believe it also intends that the member
function declarations should not be semantically validated until the
class has been completely declared.

If this isn't allowed, I don't know how else a member function could be
declared to throw an object of its own class.

John Spicer:
The type is considered complete within function bodies, but not in their
declaration (see 9.2 [class.mem] paragraph 2).

Proposed Resolution:

Change 9.2 [class.mem] paragraph 2 as follows:

Within the class member-specification, the class is regarded
as complete within function bodies, default arguments,
exception-specifications, and constructor
ctor-initializers (including such things in nested classes).

Rationale: Taken with 8.3.5 [dcl.fct] paragraph 6, the
exception-specification is the only part of a function
declaration/definition in which the class name cannot be used because
of its putative incompleteness. There is no justification for
singling out exception specifications this way; both in the function
body and in a catch clause, the class type will be complete,
so there is no harm in allowing the class name to be used in the
exception-specification.

613.
Unevaluated uses of non-static class members

According to 9.2 [class.mem] paragraph 9, the name of a
non-static data member can only be used with an object reference
(explicit or implied by the this pointer of a non-static
member function) or to form a pointer to member. This restriction
applies even in the operand of sizeof, although the
operand is not evaluated and thus no object is needed to perform the
operation. Consequently, determining the size of a non-static class
member often requires a circumlocution like

sizeof((C*) 0)->m

instead of the simpler and more obvious (but incorrect)

sizeof(C::m)

The CWG considered this question as part of
issue 198 and decided at that time to
retain the restriction on consistency grounds: the rule was
viewed as applying uniformly to expressions, and making an
exception for sizeof would require introducing a
special-purpose “wart.”

The issue has recently resurfaced, in part due to the fact that
the restriction would also apply to the decltype operator.
Like the unary & operator to form a pointer to member,
sizeof and decltype need neither an lvalue nor
an rvalue, requiring solely the declarative information of the
named operand. One possible approach would be to define the concept
of “unevaluated operand” or the like, exempt unevaluated
operands from the requirement for an object reference in
9.2 [class.mem] paragraph 9, and then define the operands
of these operators as “unevaluated.”

620.
Declaration order in layout-compatible POD structs

[Voted into the WP at the July, 2007 meeting as part of paper
J16/07-0202 = WG21 N2342.]

It should be made clear in 9.2 [class.mem] paragraph 15,

Two POD-struct (clause 9 [class]) types are
layout-compatible if they have the same number of non-static data
members, and corresponding non-static data members (in order) have
layout-compatible types (3.9 [basic.types]).

that “corresponding... (in order)” refers to declaration
order and not the order in which the members are laid out in memory.

However, this raises the point that, in cases where an
access-specifier is involved, the declaration and layout
order can be different (see paragraph 12). Thus, for two POD-struct
classes A and B,

struct A {
char c;
int i;
}
struct B {
char c;
public:
int i;
};

a compiler could move B::i before B::c, but
A::c must precede A::i. It does not seem
reasonable that these two POD-structs would be considered
layout-compatible, even though they satisfy the requirement that
corresponding members in declaration order are layout-compatible.

One possibility would be to require that neither POD-struct have
an access-specifier in order to be considered
layout-compatible. (It's not sufficient to require that they have
the same access-specifiers, because the compiler is not
required to lay out the storage the same way for different classes.)

8.5.1 [dcl.init.aggr] paragraph 2 should also be clarified
to make explicit that “increasing... member order” refers
to declaration order.

Proposed resolution (April, 2007):

This issue will be resolved by the adoption of the POD proposal
(currently J16/07-0090 = WG21 N2230). That paper does not propose
a change to the wording of 8.5.1 [dcl.init.aggr] paragraph 2,
but the CWG feels that the intent of that paragraph (that the
initializers are used in declaration order) is clear enough not to
require revision.

452.
Wording nit on description of this

9.3.2 [class.this] paragraph 1, which specifies the
meaning of the
keyword 'this', seems to limit its usage to the *body* of non-static
member functions. However 'this' is also usable in ctor-initializers
which, according to the grammar in
8.4 [dcl.fct.def] par. 1, are not
part of the body.

Proposed resolution: Changing the first part of
9.3.2 [class.this] par. 1 to:

In the body of a nonstatic (9.3) member function or in a
ctor-initializer (12.6.2), the keyword this is a non-lvalue
expression whose value is the address of the object for which
the function is called.

NOTE: I'm talking of constructors as functions that are "called";
there have been discussions on c.l.c++.m as to whether constructors
are "functions" and to whether this terminology is correct or not; I
think it is both intuitive and in agreement with the standard wording.

Steve Adamczyk: See also issue 397,
which is defining a new syntax term for the body of a function
including the ctor-initializers.

An informal reference to the body of a function should be
interpreted as a reference to the nonterminal function-body.

Change the definition of function-try-block in
15 [except] paragraph 1:

function-try-block:

try ctor-initializeroptfunction-bodycompound-statement handler-seq

Change 3.3.7 [basic.scope.class] paragraph 1, point 1, as
indicated:

The potential scope of a name declared in a class consists not only of
the declarative region following the name's point of declaration, but
also of all function bodies,bodies and default
arguments, and constructor ctor-initializers in that
class (including such things in nested classes).

Change 3.3.7 [basic.scope.class] paragraph 1, point 5, as
indicated:

The potential scope of a declaration that extends to or past the end
of a class definition also extends to the regions defined by its
member definitions, even if the members are defined lexically outside
the class (this includes static data member definitions, nested class
definitions, member function definitions (including the member
function body and, for constructor functions (12.1 [class.ctor]), the ctor-initializer (12.6.2 [class.base.init]))
and any portion of the declarator part of such definitions which
follows the identifier, including a parameter-declaration-clause
and any default arguments (8.3.6 [dcl.fct.default]).
[Example:...

That is, an unqualified name that occurs, for instance, in a type or
default argument expression in the parameter-declaration-clause,parameter-declaration-clause or in the function body,
or in an expression of a mem-initializer in a constructor
definition.

Change 5.1.1 [expr.prim.general] paragraph 3 as indicated:

...The keyword this shall be used only inside a non-static
class member function body (9.3 [class.mfct]) or in a
constructor mem-initializer (12.6.2 [class.base.init])...

Change 9.2 [class.mem] paragraph 2 as indicated:

...Within the class member-specification, the class is regarded as
complete within function bodies, default arguments, andexception-specifications, and constructor
ctor-initializers (including such things in nested classes)...

Change 9.2 [class.mem] paragraph 9 as indicated:

Each occurrence in an expression of the name of a non-static data
member or non-static member function of a class shall be expressed as
a class member access (5.2.5 [expr.ref]), except when it
appears in the formation of a pointer to member (5.3.1 [expr.unary.op]), oror when it appears in the body of
a non-static member function of its class or of a class derived from
its class (9.3.1 [class.mfct.non-static]), or when it appears in
a mem-initializer for a constructor for its class or for a
class derived from its class (12.6.2 [class.base.init]).

Change the note in 9.3 [class.mfct] paragraph 5 as
indicated:

[Note: a name used in a member function definition (that is, in the
parameter-declaration-clause including the default arguments
(8.3.6 [dcl.fct.default]), oror in the member
function body, or, for a constructor function (12.1 [class.ctor]), in a mem-initializer expression (12.6.2 [class.base.init])) is looked up as described in 3.4 [basic.lookup]. —end note]

Change 9.3.1 [class.mfct.non-static] paragraph 1 as indicated:

...A non-static member function may also be called directly using
the function call syntax (5.2.2 [expr.call], 13.3.1.1 [over.match.call]) from within the body of a member function of its class or of a class derived from its class.

from within the body of a member function of its class or of a
class derived from its class, or

from a mem-initializer (12.6.2 [class.base.init]) for
a constructor for its class or for a class derived from its class.

Change 9.3.1 [class.mfct.non-static] paragraph 3 as indicated:

When an id-expression (5.1.1 [expr.prim.general]) 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 Xor 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, 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...

Change 12.1 [class.ctor] paragraph 7 as indicated:

...The implicitly-defined default constructor performs the set of
initializations of the class that would be performed by a user-written
default constructor for that class with an
empty mem-initializer-listno ctor-initializer (12.6.2 [class.base.init])
and an empty function bodycompound-statement...

Change 12.6.2 [class.base.init] paragraph 4 as indicated:

...After the call to a constructor for class X has completed, if a
member of X is neither specified in the constructor’s
mem-initializers, nor default-initialized, nor
value-initialized, nor given a value during execution
of the compound-statement of the body of the
constructor, the member has indeterminate value.

Change the last bullet of 12.6.2 [class.base.init]
paragraph 5 as indicated:

Finally, the bodycompound-statement of the
constructor body is executed.

Change 15 [except] paragraph 4 as indicated:

A function-try-block associates a handler-seq with the
ctor-initializer, if present, and the function-bodycompound-statement. An exception thrown during the
execution of the initializer expressions in
the ctor-initializer or during the execution of
the function-bodycompound-statement
transfers control to a handler in a
function-try-block in the same way as an exception thrown
during the execution of a try-block transfers control to other
handlers. [Example:

When an exception is thrown, control is transferred to the nearest
handler with a matching type (15.3 [except.handle]);
“nearest” means the handler for which the
compound-statement,compound-statement
orctor-initializer, or function-body following
the try keyword was most recently entered by the thread of
control and not yet exited.

We are not quite sure about what an "unnamed class" is.
There is no exact definition in ISO/IEC 14882; the closest we can come to a
hint is the wording of section 7.1.3 [dcl.typedef]
paragraph 5, where it seems to be understood that a class-specifier with no
identifier between "class" and "{" is unnamed. The identifier provided after
"}" ( "A" in the test case above) is there for "linkage purposes" only.

To us, class B::A in the test program above seems "named"
enough, and there is certainly a mechanism to provide the definition for
B::A::i (in contrast to the note in section 9.4.2 [class.static.data]
paragraph 5).

Our position is therefore that the above test program is
indeed legal C++. Can you confirm or reject this claim?

Herb Sutter replied to the submitter as follows:
Here are my notes based on a grep for
"unnamed class" in the standard:

3.5 [basic.link] paragraph 4, bullet 3, makes a note that
does not directly speak to your question but which draws the same distinction:

a named class (clause class), or an unnamed class defined in a
typedef declaration in which the class has the typedef name for
linkage purposes (7.1.3 [dcl.typedef]);

Likewise in your example, you have an unnamed class defined in a
typedef declaration.

9.4.2 [class.static.data] paragraph 5 does indeed appear to
me to make your example not supported by ISO C++ (although implementations
could allow it as an extension, and many implementation do happen to allow it).

7.1.3 [dcl.typedef] paragraph 5 does indeed likewise confirm
the interpretation you give of an unnamed class.

So yes, an unnamed class is one where there is no identifier (class
name) between the class-key and the {. This is also in harmony with the
production for class-name in 9 [class] paragraph 1:

class-name:

identifiertemplate-id

Notes from the October 2003 meeting:

We agree that the example is not valid; this is an unnamed class.
We will add wording to define an unnamed class. The note in
9.4.2 [class.static.data] paragraph 5 should be corrected
or deleted.

Proposed Resolution (October 2003):

At the end of clause 9 [class],
paragraph 1, add the following:

A class-specifier where the class-head omits
the optional identifier defines an unnamed class.

Delete the following from 9.4.2 [class.static.data] paragraph 5:

[ Note: this is because there is no mechanism to provide the
definitions for such static data members. ]

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

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:

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

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:

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):

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.

Change the first sentence of 9.4.2 [class.static.data]
paragraph 2 as indicated:

If a static data member is of const integral or const enumeration
type, its declaration in the class definition can specify a
constant-initializerwhichwhose 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]
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"?

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.

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.

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.

198.
Definition of "use" in local and nested classes

Declarations in a local class can use only type names, static
variables, extern variables and functions, and enumerators
from the enclosing scope.

The definition of when an object or function is "used" is found in
3.2 [basic.def.odr]
paragraph 2 and
essentially says that the operands of sizeof and
non-polymorphic typeid operators are not used. (The
resolution for issue 48 will add
contexts in which integral constant expressions are required to the
list of non-uses.)

This definition of "use" would presumably allow code like

void foo() {
int i;
struct S {
int a[sizeof(i)];
};
};

which is required for C compatibility.

However, the restrictions on nested classes in
9.7 [class.nest]
paragraph 1 are very
similar to those for local classes, and the example there explicitly
states that a reference in a sizeof expression is a forbidden
use (abbreviated for exposition):

[As a personal note, I have seen real-world code that was exactly like
this; it was hard to persuade the author that the required
writearound, sizeof(((enclose*) 0)->x), was an improvement
over sizeof(x). —wmm]

Similarly, 9.2 [class.mem] paragraph 9 would appear to
prohibit examples like the following:

struct B {
char x[10];
};
struct D: B {
char y[sizeof(x)];
};

Suggested resolution: Add cross-references to
3.2 [basic.def.odr]
following the word
"use" in both 9.7 [class.nest]
and
9.8 [class.local]
, and change the example
in 9.7 [class.nest]
to indicate that a
reference in a sizeof expression is permitted. In
9.2 [class.mem] paragraph 9, "referred to" should be
changed to "used" with a cross_reference to
3.2 [basic.def.odr].

Notes from 10/01 meeting:

It was noted that the suggested resolution did not make the
sizeof() example in 9.7 [class.nest] valid.
Although the reference to the argument of sizeof() is not regarded
as a use, the right syntax must be used nonetheless to reference a non-static
member from the enclosing class. The use of the member name by itself is not
valid. The consensus within the core working group was that nothing should be
done about this case. It was later discovered that
9.4 [class.static] paragraph 3 states that

The
definition of a static
member shall not use directly the names of the nonstatic members of its class
or of a base class of its class (including as operands of the sizeof
operator). The definition of a static member may only refer to
these members to
form pointer to members (5.3.1 [expr.unary.op]) or
with the class member access syntax (5.2.5 [expr.ref]).

This seems to
reinforce the decision of the working group.

The use of "use" should still be cross-referenced. The
statements in 9.7 [class.nest] and 9.8 [class.local]
should also be rewritten to state the requirement
positively rather than negatively as the list of "can't"s is already missing
some cases such as template parameters.

Notes from the 4/02 meeting:

We backed away from "use" in the technical sense, because the
requirements on the form of reference are the same whether or not
the reference occurs inside a sizeof.

Proposed Resolution (revised October 2002):

In 9.2 [class.mem] paragraph 9, replace

Except when used to form a pointer to member
(5.3.1 [expr.unary.op]), when used in the body of a
nonstatic member function of
its class or of a class derived from its class
(9.3.1 [class.mfct.non-static]), or when used in
a mem-initializer for a
constructor for its class or for a class derived from its class
(12.6.2 [class.base.init]), a nonstatic data or function member
of a class shall only be referred to with the class member access syntax
(5.2.5 [expr.ref]).

with the following paragraph

Each occurrence in an expression of the name of a nonstatic data
member or nonstatic member function of a class shall be expressed as a class
member access (5.2.5 [expr.ref]), except when it appears
in the formation of a pointer to member
(5.3.1 [expr.unary.op]), when it appears in the body
of a nonstatic member function
of its class or of a class derived from its class
(9.3.1 [class.mfct.non-static]), or when it appears in a
mem-initializer for
a constructor for its class or for a class derived from its class
(12.6.2 [class.base.init]).

In 9.7 [class.nest]
paragraph 1, replace the last sentence,

Except by using explicit pointers, references, and object names,
declarations in a nested class can use only type names, static members, and
enumerators from the enclosing class.

with the following

[Note: In accordance with 9.2 [class.mem],
except by using explicit pointers,
references, and object names, declarations in a nested class shall not use
nonstatic data members or nonstatic member functions from the
enclosing class. This restriction applies in all constructs including the
operands of the sizeof operator.]

In the example following 9.7 [class.nest]
paragraph 1, change the comment on the first statement of
function f to emphasize that sizeof(x) is an error. The
example reads in full:

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

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:

A typedef-name (7.1.3 [dcl.typedef]) that names a
class type, or a cv-qualified version thereof, is also
a class-name, butclass-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.

Delete 7.1.3 [dcl.typedef] paragraph 8:

[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;

This is a name lookup ambiguity because of 10.2 [class.member.lookup]
paragraph 2:

... 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 [namespace.udecl]
.

Proposed Resolution (10/00):

Replace the two cited sentences from 10.2 [class.member.lookup]
paragraph 2 with the following:

The resulting set of declarations shall all be from sub-objects
of the same type, or there shall be a set of declarations from
sub-objects of a single type that contains using-declarations
for the declarations found in all other sub-object types.
Furthermore, for nonstatic members, the resulting set of
declarations shall all be from a single sub-object, or there shall
be a set of declarations from a single sub-object that contains
using-declarations for the declarations found in all other
sub-objects. Otherwise, there is an ambiguity and the program is
ill-formed.

Replace the examples in 10.2 [class.member.lookup]
paragraph 3 with the following:

... 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.

Since the two x's are considered to be "from" different objects, looking up
x produces a set including declarations "from" different objects, and the
program is ill-formed. Clearly this is wrong. The problem with the
existing wording is that it fails to consider lookup context.

The first proposed solution:

The resulting set of declarations shall all be from sub-objects
of the same type, or there shall be a set of declarations from
sub-objects of a single type that contains using-declarations
for the declarations found in all other sub-object types.
Furthermore, for nonstatic members, the resulting set of
declarations shall all be from a single sub-object, or there shall
be a set of declarations from a single sub-object that contains
using-declarations for the declarations found in all other
sub-objects. Otherwise, there is an ambiguity and the program is
ill-formed.

because it considers the lookup context, but not the definition context;
under this definition of "from", the two declarations found are the
using-declarations, which are "from" B1 and B2.

The solution is to separate the notions of lookup and definition context.
I have taken an algorithmic approach to describing the strategy.

Incidentally, the earlier proposal allows one base to have a superset of
the declarations in another base; that was an extension, and my proposal
does not do that. One algorithmic benefit of this limitation is to
simplify the case of a virtual base being hidden along one arm and not
another ("domination"); if we allowed supersets, we would need to remember
which subobjects had which declarations, while under the following
resolution we need only keep two lists, of subobjects and declarations.

Proposed resolution (October 2002):

Replace 10.2 [class.member.lookup] paragraph 2 with:

The following steps define the result of name lookup for a member
name f in a class scope C.

The lookup set for f in C, called S(f,C), consists of two
component sets: the declaration set, a set of members named f; and
the subobject set, a set of subobjects where declarations of these
members (possibly including using-declarations) were found. In the
declaration set, using-declarations are replaced by the members they
designate, and type declarations (including injected-class-names) are
replaced by the types they designate. S(f,C) is calculated as
follows.

If C contains a declaration of the name f, the declaration set contains
every declaration of f in C (excluding bases), the subobject set contains C
itself, and calculation is complete.

Otherwise, S(f,C) is initially empty. If C has base classes, calculate
the lookup set for f in each direct base class subjobject Bi,
and merge each such lookup set S(f,Bi) in turn into S(f,C).

The following steps define the result of merging lookup set
S(f,Bi) into the intermediate S(f,C):

If each of the subobject members of S(f,Bi) is a base
class subobject of at least one of the subobject members of S(f,C), S(f,C)
is unchanged and the merge is complete. Conversely, if each of the
subobject members of S(f,C) is a base class subobject of at least one of
the subobject members of S(f,Bi), the new S(f,C) is a copy of
S(f,Bi).

Otherwise, if the declaration sets of S(f,Bi) and S(f,C)
differ, the merge is ambiguous: the new S(f,C) is a lookup set with an
invalid declaration set and the union of the subobject sets. In subsequent
merges, an invalid declaration set is considered different from any
other.

Otherwise, consider each declaration d in the set, where d is a
member of class A. If d is a nonstatic member, compare the A base class
subobjects of the subobject members of S(f,Bi) and
S(f,C). If they do not match, the merge is ambiguous, as in the
previous step. [Note: It is not necessary to remember which A subobject
each member comes from, since using-declarations don't disambiguate. ]

Otherwise, the new S(f,C) is a lookup set with the shared
set of declarations and the union of the subobject sets.

The result of name lookup for f in C is the declaration set of
S(f,C). If it is an invalid set, the program is ill-formed.

S(x,F) is unambiguous because the A and B base subobjects of D are also
base subobjects of E, so S(x,D) is discarded in the first merge step. --end
example]

Turn 10.2 [class.member.lookup] paragraphs 5 and 6 into notes.

Notes from October 2003 meeting:

Mike Miller raised some new issues in N1543, and we adjusted the
proposed resolution as indicated in that paper.

Further information from Mike Miller (January 2004):

Unfortunately, I've become aware of a minor glitch in
the proposed resolution for issue 39 in N1543, so I'd like to
suggest a change that we can discuss in Sydney.

A brief review and background of the problem: the major change we
agreed on in Kona was to remove detection of multiple-subobject
ambiguity from class lookup (10.2 [class.member.lookup]) and instead
handle it as part
of the class member access expression. It was pointed out in
Kona that 11.2 [class.access.base]/5 has this effect:

If a class member access operator, including an implicit
"this->," is used to access a nonstatic data member or
nonstatic member function, the reference is ill-formed if the
left operand (considered as a pointer in the "." operator
case) cannot be implicitly converted to a pointer to the
naming class of the right operand.

After the meeting, however, I realized that this requirement is
not sufficient to handle all the cases. Consider, for instance,

Here, both the object expression ("this") and the naming class
are "D", so the reference to "i" satisfies the requirement in
11.2 [class.access.base]/5, even though it involves a
multiple-subobject ambiguity.

In order to address this problem, I proposed in N1543 to add a
paragraph following 5.2.5 [expr.ref]/4:

If E2 is a non-static data member or a non-static member
function, the program is ill-formed if the class of E1 cannot
be unambiguously converted (10.2) to the class of which E2 is
directly a member.

That's not quite right. It does diagnose the case above as
written; however, it breaks the case where qualification is used
to circumvent the ambiguity:

In my proposed wording, the class of "this" can't be converted to
"B" (the qualifier is ignored), so the access is ill-formed.
Oops.

I think the following is a correct formulation, so the proposed
resolution we discuss in Sydney should contain the following
paragraph instead of the one in N1543:

If E2 is a nonstatic data member or a non-static member
function, the program is ill-formed if the naming class
(11.2) of E2 cannot be unambiguously converted (10.2) to
the class of which E2 is directly a member.

This reformulation also has the advantage of pointing readers to
11.2 [class.access.base], where the the convertibility requirement
from the class of
E1 to the naming class is located and which might otherwise be
overlooked.

Notes from the March 2004 meeting:

We discussed this further and agreed with these latest
recommendations. Mike Miller has produced a paper N1626 that gives
just the final collected set of changes.

390.
Pure virtual must be defined when implicitly called

A pure virtual function need be defined only if explicitly called with
the qualified-id syntax (5.1.1 [expr.prim.general]).

This is IMHO incomplete. A dtor is a function (well, a "special member
function", but this also makes it a function, right?) but it is called
implicitly and thus without a qualified-id syntax. Another alternative
is that the pure virtual function is called directly or indirectly from
the ctor. Thus the above sentence which specifies when a pure virtual
function need be defined ("...only if...") needs to be extended:

A pure virtual function need be defined only if explicitly called with
the qualified-id syntax (5.1.1 [expr.prim.general]) or if implicitly
called (12.4 [class.dtor] or 12.7 [class.cdtor]).

Proposed resolution:

Change 10.4 [class.abstract] paragraph 2 from

A pure virtual function need be defined only if explicitly called
with the qualified-id syntax (5.1.1 [expr.prim.general]).

to

A pure virtual function need be defined only if
explicitly called with, or as if with
(12.4 [class.dtor]),
the qualified-id syntax (5.1.1 [expr.prim.general]).

Note: 12.4 [class.dtor] paragraph 6 defines the "as if"
cited.

8.
Access to template arguments used in a function return type and in the nested name specifier

All access controls in clause 11 affect the ability to access a class
member name from a particular scope... In particular, access controls
apply as usual to member names accessed as part of a function return type,
even though it is not possible to determine the access privileges of that
use without first parsing the rest of the function declarator.

This means, if we take the loosest possible definition of "access from
a particular scope", that we have to save and check later the following
names

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.7 [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?

Proposed resolution (04/01):

The resolution for this issue is contained in the resolution
for issue 45.

494.
Problems with the resolution of issue 45

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:

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.

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.7 [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.3 [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,

This seems to be an oversight. The proposed change to
11.7 [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.

Like a member function, a friend function (11.3 [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.

9.
Clarification of access to base class members

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.

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*.

(See J16/99-0042 = WG21 N1218.)

Proposed Resolution (04/01):

Add preceding 11.2 [class.access.base]
paragraph 4:

A base class B of N is accessible at R,
if

an invented public member of B would be a public member
of N, or

R occurs in a member or friend of class N, and an
invented public member of B would be a private or protected
member of N, or

R occurs in a member or friend of a class P derived
from N, and an invented public member of B would be
a private or protected member of P, or

there exists a class S such that B is a base class
of S accessible at R and S is a base class
of N accessible at R. [Example:

77.
The definition of friend does not allow nested classes to be friends

A friend of a class is a function or class that is not a member
of the class but is permitted to use the private and protected member names
from the class. ...

A nested class, i.e. INNER in the example below, is a member of class OUTER.
The sentence above states that it cannot be a friend. I think this is a
mistake.

class OUTER {
class INNER;
friend class INNER;
class INNER {};
};

Proposed resolution (04/01):

Change the first sentence of 11.3 [class.friend]
as follows:

A friend of a class is a function or class that is not a
member of the class but is allowedgiven permission
to use the private and protected member names from the class.
The name of a friend is not in the scope of the class, and
the friend is not called with the member access operators
(5.2.5 [expr.ref]) unless it is a member of
another class.A class specifies its friends, if any,
by way of friend declarations. Such declarations give special
access rights to the friends, but they do not make the nominated
friends members of the befriending class.

#410-D: protected function "A::g" is not accessible through a "B" pointer or object
b.g();
^

Steve Adamczyk:
The error in this case is due to
11.4 [class.protected] of the standard, which is an additional
check on top of the other access checking. When that section says
"a protected nonstatic member function ... of a base class" it doesn't
indicate whether the fact that there is a using-declaration is relevant.
I'd say the current wording taken at face value would suggest that
the error is correct -- the function is protected, even if the
using-declaration for it makes it accessible as a public function.
But I'm quite sure the wording in
11.4 [class.protected] was written before using-declarations
were invented and has not been reviewed since for consistency with
that addition.

Notes from April 2003 meeting:

We agreed that the example should be allowed.

Proposed resolution (April 2003, revised October 2003):

Change 11.4 [class.protected] paragraph 1 from

When a friend or a member function of a derived class references a
protected nonstatic member function or protected nonstatic data member
of a base class, an access check applies in addition to those
described earlier in clause 11 [class.access].
[Footnote: This
additional check does not apply to other members, e.g. static
data members or enumerator member constants.] Except
when forming a pointer to member (5.3.1 [expr.unary.op]),
the access must be through a
pointer to, reference to, or object of the derived class itself (or
any class derived from that class (5.2.5 [expr.ref]).
If the access is to form a
pointer to member, the nested-name-specifier shall name the
derived class (or any class derived from that class).

to

An additional access check beyond those described earlier in
clause 11 [class.access]
is applied when a nonstatic data member or nonstatic member
function is a protected member of its naming class
(11.2 [class.access.base]).
[Footnote: This additional check does not apply
to other members, e.g., static data members or enumerator member
constants.] As described
earlier, access to a protected member is granted because the
reference occurs in a friend or member of some
class C. If the access is to form a pointer to member
(5.3.1 [expr.unary.op]), the
nested-name-specifier shall name C or a
class derived from C. All other accesses involve a
(possibly implicit) object expression (5.2.5 [expr.ref]).
In this case, the
class of the object expression shall be C or a class derived
from C.

I think the formulation that the member is a protected member
of its naming class is not what we want. I think we intended
that the member is protected in the declaration that is found,
where the declaration found might be a using-declaration.

Mike Miller: I think the proposed wording makes the
access pb->p ill-formed, and I think that's the right
thing to do.

First, protected inheritance of A by B means
that B intends the public and protected members of
A to be part of B's implementation, available
to B's descendants only. (That's why there's a
restriction on converting from B* to A*, to
enforce B's intention on the use of members of
A.) Consequently, I see no difference in access policy
between your example and

class B {
protected:
int p;
};

Second, the reason we have this rule is that C's use
of inherited protected members might be different from their use
in a sibling class, say D. Thus members and friends of
C can only use B::p in a manner consistent with
C's usage, i.e., in C or
derived-from-C objects. If we rewrote your example
slightly,

This is because the nested class does not have access to the member E
in D. 11 [class.access]
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 [class.access]
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:

If the return type (i.e. C::B) is access checked in the scope
of class B (as implied by
11 [class.access]
paragraph 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.

Proposed resolution (04/01):

The resolution for this issue is incorporated into the
resolution for issue 45.

private; that is, its name can be used only by members and
friends of the class in which it is declared. [...]

and
11.7 [class.access.nest]
paragraph 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 11 [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.7 [class.access.nest]
paragraph 2. 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.

Insert the following as a new paragraph following
11 [class.access] paragraph 1:

A member of a class can also access all names as the class of which
it is a member. A local class of a member function may access the
same names that the member function itself may access. [Footnote:
Access permissions are thus transitive and cumulative to nested and
local classes.]

Delete 11 [class.access] paragraph 6.

In 11.7 [class.access.nest] paragraph 1, change

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 11 [class.access]) shall be obeyed.

to

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

263.
Can a constructor be declared a friend?

According to 12.1 [class.ctor] paragraph 1, a
declaration of a constructor has a special limited syntax, in
which only function-specifiers are allowed. A friend
specifier is not a function-specifier, so one interpretation
is that a constructor cannot be declared in a friend
declaration.

(It should also be noted, however, that neither friend
nor function-specifier is part of the declarator
syntax, so it's not clear that anything conclusive can be derived
from the wording of 12.1 [class.ctor].)

Notes from 04/01 meeting:

The consensus of the core language working group was that it
should be permitted to declare constructors as friends.

Proposed Resolution (revised October 2002):

Change paragraph 1a in 3.4.3.1 [class.qual] (added by
the resolution of issue 147) as follows:

If the nested-name-specifier nominates a class C, and the
name specified after the nested-name-specifier, when looked up in
C, is the injected-class-name of C (clause
9 [class]), the name is instead considered to name the
constructor of class C. Such a constructor name shall be used
only in the declarator-id of a constructor definitiondeclaration that appears outside of the class definitionnames a constructor....

Note: the above does not allow qualified names to be used for
in-class declarations; see 8.3 [dcl.meaning] paragraph 1.
Also note that issue 318 updates the
same paragraph.

326.
Wording for definition of trivial constructor

In 12.1 [class.ctor] paragraph 5, the standard says
"A constructor is trivial if [...]", and goes on to define a trivial
default constructor. Taken literally, this would mean that a copy
constructor can't be trivial (contrary to 12.8 [class.copy] paragraph 6). I suggest changing this to "A default
constructor is trivial if [...]". (I think the change is purely
editorial.)

Proposed Resolution (revised October 2002):

Change 12.1 [class.ctor] paragraph 5-6 as follows:

A default constructor for a class X
is a constructor of class X
that can be called without an argument.
If there is no
user-declareduser-declared
constructor for class X,
a default constructor is implicitly declared.
An
implicitly-declaredimplicitly-declared
default constructor
is an inline public member of its class.
A
default
constructor is trivial
if it is an implicitly-declared default constructor
and if:

its class has no virtual functions (10.3 [class.virtual])
and no virtual base classes (10.1 [class.mi]), and

all the direct base classes of its class
have trivial
default
constructors, and

for all the nonstatic data members of its class
that are of class type (or array thereof),
each such class has a trivial
default
constructor.

Otherwise, the
default
constructor is non-trivial.

Change 12.4 [class.dtor] paragraphs 3-4 as follows (the main
changes are removing italics):

If a class has no
user-declareduser-declared
destructor, a destructor is declared
implicitly. An
implicitly-declaredimplicitly-declared
destructor is an inline public
member of its class. A destructor is trivial if it is an
implicitly-declared destructor and if:

all of the direct base classes of its class have trivial destructors and

for all of the non-static data members of its class that are of
class type (or array thereof), each such class has a trivial
destructor.

331.
Allowed copy constructor signatures

A copy constructor for a class X is a constructor with a
first parameter of type X & or of type const X &. [Note:
see 12.8 [class.copy] for more information on copy constructors.]

No mention is made of constructors with first parameters of types
volatile X & or const volatile X &. This statement seems to be
in contradiction with 12.8 [class.copy] paragraph 2 which states

A non-template constructor for class X is a copy constructor
if its first parameter is of type X &, const X &, volatile X &
or const volatile X &, ...

12.8 [class.copy] paragraph 5 also mentions the volatile
versions of the
copy constructor, and the comparable paragraphs for copy assignment
(12.8 [class.copy] paragraphs 9 and 10) all allow volatile
versions, so it seems that 12.1 [class.ctor] is at fault.

Proposed resolution (October 2002):

Change 12.1 [class.ctor] paragraph 10 from

A copy constructor for a class X is a constructor with a
first parameter of type X& or of type const X&.
[Note: see 12.8 [class.copy] for more information on
copy constructors. ]

to (note that the dropping of italics is intentional):

A copy constructor (12.8 [class.copy]) is used to copy objects
of class type.

86.
Lifetime of temporaries in query expressions

In
12.2 [class.temporary]
paragraph 5,
should binding a reference to the result of a "?" operation, each
of whose branches is a temporary, extend both temporaries?

Here's an example:

const SFileName &C = noDir ? SFileName("abc") : SFileName("bcd");

Do the temporaries created by the SFileName conversions survive
the end of the full expression?

Notes from 10/00 meeting:

Other problematic examples include cases where the temporary
from one branch is a base class of the temporary from the other (i.e.,
where the implementation must remember which type of temporary must
be destroyed), or where one branch is a temporary and the other is
not. Similar questions also apply to the comma operator. The sense
of the core language working group was that implementations should
be required to support these kinds of code.

Notes from the March 2004 meeting:

We decided that the cleanest model is one in which any "?" operation
that returns a class rvalue always copies one of its operands to
a temporary and returns the temporary as the result of the operation.
(Note that this may involve slicing.) An implementation would be
free to optimize this using the rules in 12.8 [class.copy]
paragraph 15, and in fact we would expect that in many cases
compilers would do such optimizations. For example, the compiler
could construct both rvalues in the above example into a
single temporary, and thus avoid a copy.

124.
Lifetime of temporaries in default initialization of class arrays

Jack Rouse:
12.2 [class.temporary]
states that temporary objects will normally be destroyed at the
end of the full expression in which they are created. This can create
some unique code generation requirements when initializing a class
array with a default constructor that uses a default argument. Consider
the code:

The full expression allocating the array in f(int) includes the
default constructor for S. Therefore according to
1.9 [intro.execution] paragraph 14, it
includes the default argument expression for S(int).
So evaluation of
the full expression should include evaluating the default argument "n"
times and creating "n" temporaries of type T. But the destruction of
the temporaries must be delayed until the end of the full expression
so this requires allocating space at runtime for "n" distinct
temporaries. It is unclear how these temporaries are supposed to be
allocated and deallocated. They cannot readily be autos because a
variable allocation is required.

I believe that many existing implementations will destroy the
temporaries needed by the default constructor after each array element
is initialized. But I can't find anything in the standard that allows
the temporaries to be destroyed early in this case.

I think the standard should allow the early destruction of temporaries
used in the default initialization of class array elements. I believe
early destruction is the status quo, and I don't think the users of
existing C++ compilers have been adversely impacted by it.

199.
Order of destruction of temporaries

[Voted into the WP at the April, 2007 meeting as part of paper
J16/07-0099 = WG21 N2239.]

12.2 [class.temporary]
paragraph 3 simply
states the requirement that temporaries created during the evaluation
of an expression

are destroyed as the last step in evaluating the
full-expression (1.9) that (lexically) contains the point where they
were created.

There is nothing said about the relative order in which these
temporaries are destroyed.

Paragraph 5, dealing with temporaries bound to references, says

the temporaries created during the evaluation of the expression
initializing the reference, except the temporary to which the
reference is bound, are destroyed at the end of the full-expression in
which they are created and in the reverse order of the completion of
their construction.

Is this difference intentional? May temporaries in expressions other
than those initializing references be deleted in non-LIFO order?

Notes from 04/00 meeting:

Steve Adamczyk expressed concern about constraining implementations
that are capable of fine-grained parallelism -- they may be
unable to determine the order of construction without adding
undesirable overhead.

Proposed resolution (April, 2007):

As specified in paper J16/07-0099 = WG21 N2239.

201.
Order of destruction of temporaries in initializers

According to 12.2 [class.temporary]
paragraph 4, an expression appearing as the initializer in an object
definition constitutes a context "in which temporaries are destroyed
at a different point than the end of the full-expression." It goes on
to say that the temporary containing the value of the expression
persists until after the initialization is complete (see also
issue 117). This seems to presume
that the end of the full-expression is a point earlier than the
completion of the initialization.

However, according to
1.9 [intro.execution]
paragraphs 12-13, the
full-expression in such cases is, in fact, the entire initialization.
If this is the case, the behavior described for temporaries in an
initializer expression is simply the normal behavior of temporaries in
any expression, and treating it as an exception to the general rule is
both incorrect and confusing.

If the initializer for an object or
sub-object is a full-expression, the initialization of
the object or sub-object (e.g., by calling a constructor
or copying an expression value) is considered to be part
of the full-expression.

Replace 12.2 [class.temporary] paragraph 4 with:

There are two contexts in which temporaries are
destroyed at a different point than the end of the
full-expression. The first context is when a
default constructor is called to initialize an
element of an array. If the constructor has one
or more default arguments, any temporaries created
in the default argument expressions are destroyed
immediately after return from the constructor.

a=f(a) requires a temporary for either the argument a
or the result of f(a) to avoid undesired aliasing of a.

The note seems to imply that an implementation is allowed to omit
copying "a" to f's formal argument, or to omit using a temporary for
the return value of f. I don't find that license in normative text.

Function f returns an X by value, and in the expression the value is
assigned (not copy-constructed) to "a". I don't see how that
temporary can be omitted. (See also 12.8 [class.copy] p 15)

Since "a" is an lvalue and not a temporary, I don't see how copying
"a" to f's formal parameter can be avoided.

Am I missing something, or is 12.2 [class.temporary] p 2
misleading?

Proposed resolution (October, 2004):

In 12.2 [class.temporary] paragraph 2, change the last
sentence as indicated:

On the other hand, the expression a=f(a) requires a
temporary for either the argument a or the result of
f(a) to avoid undesired aliasing of athe result of f(a), which is then assigned to
a.

Section 12.2 [class.temporary] paragraph 3 says a temp is
destroyed as the last step in
evaluating the full expression. But the expression C().get() has a
reference type. Does 12.2 [class.temporary] paragraph 3 require
that the dereference to get a
boolean result occur before the destructor runs, making the code
valid? Or does the code have undefined behavior?

Bill Gibbons:
It has undefined behavior, though clearly this wasn't intended.
The lvalue-to-rvalue conversion that occurs in the "if" statement is
not currently part of the full-expression.

From section 12.2 [class.temporary] paragraph 3:

Temporary objects are destroyed as the last step in evaluating
the full-expression (1.9 [intro.execution])
that (lexically) contains the point
where they were created.

From section 1.9 [intro.execution] paragraph 12:

A full-expression is an expression that is not a subexpression
of another expression. If a language construct is defined to
produce an implicit call of a function, a use of the language
construct is considered to be an expression for the purposes
of this definition.

The note in section 1.9 [intro.execution] paragraph 12 goes
on to explain that this covers
expressions used as initializers, but it does not discuss
lvalues within temporaries.

It is a small point but it is probably worth correcting
1.9 [intro.execution] paragraph 12.
Instead of the "implicit call of a function" wording, it might
be better to just say that a full-expression includes any implicit
use of the expression value in the enclosing language construct,
and include a note giving implicit calls and lvalue-to-rvalue
conversions as examples.

A full-expression is an expression that is not a
subexpression of another expression. If a language construct is
defined to produce an implicit call of a function, a use of the
language construct is considered to be an expression for the
purposes of this definition. Conversions applied to the result of
an expression in order to satisfy the requirements of the language
construct in which the expression appears are also considered to be
part of the full-expression.

[Note: certain contexts in C++ cause the evaluation
of a full-expression that results from a syntactic construct other
than expression (5.18 [expr.comma]). For example,
in 8.5 [dcl.init] one syntax for
initializer is

( expression-list )

but the resulting construct is a function call upon a constructor
function with expression-list as an argument list; such a
function call is a full-expression. For example, in
8.5 [dcl.init], another
syntax for initializer is

= initializer-clause

but again the resulting construct might be a function call upon a
constructor function with one assignment-expression as an
argument; again, the function call is a full-expression. ][Example:

443.
Wording nit in description of lifetime of temporaries

There seems to be a typo in
12.2 [class.temporary]/5, which says "The temporary to which
the reference is bound or the temporary that is the complete object TO a
subobject OF which the TEMPORARY is bound persists for the lifetime of the
reference except as specified below."

I think this should be "The temporary to which the reference is bound or the
temporary that is the complete object OF a subobject TO which the REFERENCE
is bound persists for the lifetime of the reference except as specified
below."

I used upper-case letters for the parts I think need to be
changed.

Proposed resolution (October, 2004):

Change 12.2 [class.temporary] paragraph 5 as
indicated:

The temporary to which the reference is bound or the temporary
that is the complete object toof a subobject
ofto which the temporaryreference
is bound persists for the lifetime of the reference except as
specified below.

464.
Wording nit on lifetime of temporaries to which references are bound

[...] if obj2 is an object with static or automatic
storage duration created after the temporary is
created, the temporary shall be destroyed after
obj2 is destroyed.

For the temporary to be destroyed after obj2 is destroyed, when obj2 has
static storage, I would say that the reference to the temporary should
also have static storage, but that is IMHO not clear from the
paragraph.

Example:

void f ()
{
const T1& ref = T1();
static T2 obj2;
...
}

Here the temporary would be destoyed before obj2, contrary to the
rule above.

Steve Adamczyk: I agree there's a minor issue here. I think
the clause quoted above meant for obj1 and obj2 to have the same storage
duration. Replacing "obj2 is an object with static or automatic
storage duration" by "obj2 is an object with the same storage duration as
obj1" would, I believe, fix the problem.

Notes from October 2004 meeting:

We agreed with Steve Adamczyk's suggestion.

Proposed resolution (October, 2005):

Change 12.2 [class.temporary] paragraph 5 as follows:

... In addition, the destruction of temporaries bound to references
shall take into account the ordering of destruction of objects with
static or automatic storage duration (3.7.1 [basic.stc.static],
3.7.3 [basic.stc.auto]); that is, if obj1 is an object
with static or automatic storage duration created before the
temporary is created with the same storage duration as the
temporary, the temporary shall be destroyed before obj1
is destroyed; if obj2 is an object with static or
automatic storage duration created after the temporary is
created with the same storage duration as the temporary, the
temporary shall be destroyed after obj2 is destroyed...

296.
Can conversion functions be static?

May user-defined conversion functions be static? That is, should this
compile?

class Widget {
public:
static operator bool() { return true; }
};

All my compilers hate it. I hate it, too. However, I don't see anything
in 12.3.2 [class.conv.fct] that makes it illegal. Is this a
prohibition that arises from
the grammar, i.e., the grammar doesn't allow "static" to be followed by a
conversion-function-id in a member function declaration? Or am I just
overlooking something obvious that forbids static conversion functions?

I believe that clause 3 is correct and that clause 12 is in error.
We worked hard to get the destructor lookup rules in clause 3 to be
right, and I think we failed to notice that a change was also needed
in clause 12.

Mike Miller:

Unfortunately, I don't believe 3.4.3 [basic.lookup.qual] covers
the case of p->AB::~AB(). It's clearly intended to do so, as
evidenced by 3.4.3.1 [class.qual] paragraph 1 ("a
destructor name is looked up as specified in 3.4.3 [basic.lookup.qual]"), but I don't think the language there does so.

The relevant paragraph is 3.4.3 [basic.lookup.qual] paragraph
5. (None of the other paragraphs in that section deal with this topic
at all.) It has two parts. The first is

If a pseudo-destructor-name (5.2.4 [expr.pseudo])
contains a nested-name-specifier, the type-names are
looked up as types in the scope designated by the
nested-name-specifier.

This sentence doesn't apply, because ~AB isn't a
pseudo-destructor-name. 5.2.4 [expr.pseudo] makes
clear that this syntactic production (5.2 [expr.post]
paragraph 1) only applies to cases where the type-name is not a
class-name. p->AB::~AB is covered by the production
using id-expression.

The second part of 3.4.3 [basic.lookup.qual] paragraph 5 says

In a qualified-id of the form:

::optnested-name-specifier~class-name

where the nested-name-specifier designates a namespace name,
and in a qualified-id of the form:

::optnested-name-specifier class-name::~class-name

the class-names are looked up as types in the scope
designated by the nested-name-specifier.

This wording doesn't apply, either. The first one doesn't because
the nested-name-specifier is a class-name, not a
namespace name. The second doesn't because there's only one layer of
qualification.

As far as I can tell, there's no normative text that specifies how
the ~AB is looked up in p->AB::~AB().
3.4.3.1 [class.qual], where all the other
class member qualified lookups are handled, defers to
3.4.3 [basic.lookup.qual], and 3.4.3 [basic.lookup.qual]
doesn't cover the case.

Jason Merrill:
My thoughts on the subject were that the name we use in a destructor call
is really meaningless; as soon as we see the ~ we know what the
user means,
all we're doing from that point is testing their ability to name the
destructor in a conformant way. I think that everyone will agree that

anything::B::~B()

should be well-formed, regardless of the origins of the name "B". I
believe that the rule about looking up the second "B" in the same context
as the first was intended to provide this behavior, but to me this seems
much more heavyweight than necessary. We don't need a whole new type of
lookup to be able to use the same name before and after the ~;
we can just
say that if the two names match, the call is well-formed. This is
significantly simpler to express, both in the standard and in an
implementation.

Anyone writing two different names here is either deliberately writing
obfuscated code, trying to call the destructor of a nested class, or
fighting an ornery compiler (i.e. one that still wants to see
B_alias::~B()). I think we can ignore the first case.
The third would be
handled by reverting to the old rule (look up the name after ~ in the
normal way) with the lexical matching exception described above -- or we
could decide to break such code, do no lookup at all, and only accept a
matching name. In a good implementation, the second should probably get an
error message telling them to write Outer::Inner::~Inner instead.

We discussed this at the meetings, but I don't remember if we came to
any sort of consensus on a direction. I see three options:

Stick with the status quo, i.e. the special lookup rule such that if the
name before ::~ is a class name, the name after ::~
is looked up in the
same scope as the previous one. If we choose this option, we just need
better wording that actually expresses this, as suggested in the issue
list. This option breaks old B_alias::~B code where B_alias
is declared in a different scope from B.

Revert to the old rules, whereby the name after ::~ is looked up just
like a name after ::, with the exception that if it matches the name
before ::~ then it is considered to name the same class. This option
supports old code and code that writes B_alias::~B_alias. It does not
support the q->I1::~I2 usage of 3.4.3 [basic.lookup.qual],
but that seems like deliberate
obfuscation. This option is simpler to implement than #1.

Do no lookup for a name after ::~; it must match the
name before. This
breaks old code as #1, but supports the most important case where the
names match. This option may be slightly simpler to implement than #2.
It is certainly easier to teach.

My order of preference is 2, 3, 1.

Incidentally, it seems to me oddly inconsistent to allow
Namespace::~Class,
but not Outer::~Inner.
Prohibiting the latter makes sense from the
standpoint of avoiding ambiguity, but what was the rationale for allowing
the former?

John Spicer:
I agree that allowing Namespace::~Class is odd.
I'm not sure where this
came from. If we eliminated that special case, then I believe the #1
rule would just be that in A::B1::~B2 you look up B1
and B2 in the same place in all cases.

I don't like #2. I don't think the "old" rules represent a deliberate
design choice, just an error in the way the lookup was described. The
usage that rule permits p->X::~Y
(where Y is a typedef to X defined in X),
but I doubt people really do that. In other words, I think that #1
a more useful special case than #2 does, not that I think either special
case is very important.

One problem with the name matching rule is handling cases like:

A<int> *aip;
aip->A<int>::~A<int>(); // should work
aip->A<int>::~A<char>(); // should not

I would favor #1, while eliminating the special case of
Namespace::~Class.

Proposed resolution (10/01):

Replace the normative text of 3.4.3 [basic.lookup.qual] paragraph 5
after the first sentence with:

252.
Looking up deallocation functions in virtual destructors

There is a mismatch between 12.4 [class.dtor]
paragraph 11 and 12.5 [class.free] paragraph 4 regarding
the lookup of deallocation functions in virtual destructors.
12.4 [class.dtor] says,

At the point of definition of a virtual destructor (including an
implicit definition (12.8 [class.copy])), non-placement
operator delete shall be looked up in the scope of the destructor's
class (3.4.1 [basic.lookup.unqual]) and if found shall be accessible
and unambiguous. [Note: this assures that an operator delete
corresponding to the dynamic type of an object is available for the
delete-expression (12.5 [class.free]). ]

The salient features to note from this description are:

The lookup is "in the scope of the destructor's class," which
implies that only members are found (cf 12.2 [class.temporary]).
(The cross-reference would indicate otherwise, however, since it
refers to the description of looking up unqualified names; this kind
of lookup "spills over" into the surrounding scope.)

Only non-placement operator delete is looked up. Presumably
this means that a placement operator delete is ignored in the
lookup.

On the other hand, 12.5 [class.free] says,

If a delete-expression begins with a unary ::
operator, the deallocation 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 (12.4 [class.dtor]). 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
deallocation 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.

Points of interest in this description include:

For a class type with a virtual destructor, the lookup is
described as being "in the definition of the dynamic type's
virtual destructor," rather than "in the scope of the dynamic
type." That is, the lookup is assumed to be an unqualified
lookup, presumably terminating in the global scope.

The assumption is made that the lookup in the virtual
destructor was successful ("...the one found...", not "...the
one found..., if any"). This will not be the case if
the deallocation function was not declared as a member somewhere
in the inheritance hierarchy.

The lookup in the non-virtual-destructor case does
find placement deallocation functions and can fail as a result.

Suggested resolution: Change the description of the
lookup in 12.4 [class.dtor] paragraph 11 to match the
one in 12.5 [class.free] paragraph 4.

Proposed resolution (10/00):

Replace 12.4 [class.dtor] paragraph 11 with
the following:

At the point of definition of a virtual destructor (including an
implicit definition), the non-array deallocation function is looked up
in the scope of the destructor's class (10.2 [class.member.lookup]),
and, if no declaration is found, the function is looked up in the
global scope. If the result of this lookup is ambiguous or
inaccessible, or if the lookup selects a placement deallocation
function, the program is ill-formed. [Note: this assures that
a deallocation function corresponding to the dynamic type of an object
is available for the delete-expression (12.5 [class.free]).]

In 12.5 [class.free] paragraph 4, change

...the deallocation function is the one found by the lookup in
the definition of the dynamic type's virtual destructor
(12.4 [class.dtor]).

to

...the deallocation function is the one selected at the point of
definition of the dynamic type's virtual destructor
(12.4 [class.dtor]).

272.
Explicit destructor invocation and qualified-ids

an explicit destructor call must always be written using a member
access operator (5.2.5 [expr.ref]); in particular, the
unary-expression~X() in a member function is not an
explicit destructor call (5.3.1 [expr.unary.op]).

This note is incorrect, as an explicit destructor call can be
written as a qualified-id, e.g., X::~X(), which
does not use a member access operator.

Proposed resolution (04/01):

Change 12.4 [class.dtor] paragraph 12 as follows:

[Note: an explicit destructor call must always be written
using a member access operator (5.2.5 [expr.ref])
or a qualified-id (5.1.1 [expr.prim.general]);
in particular, the unary-expression~X() in a
member function is not an explicit destructor call
(5.3.1 [expr.unary.op]).]

677.
Deleted operator delete and virtual destructors

Deallocation functions can't be virtual because they are static
member functions; however, according to 12.5 [class.free]
paragraph 7, they behave like virtual functions when the class's
destructor is virtual:

Since member allocation and deallocation functions are static
they cannot be virtual. [Note: however, when
the cast-expression of a delete-expression refers to an
object of class type, because the deallocation function actually
called is looked up in the scope of the class that is the dynamic type
of the object, if the destructor is virtual, the effect is the same.

Because the intent is to make any use of a deleted function
diagnosable at compile time, a virtual deleted function can neither
override nor be overridden by a non-deleted function, as described
in 10.3 [class.virtual] paragraph 14:

A function with a deleted definition (8.4 [dcl.fct.def]) shall
not override a function that does not have a deleted
definition. Likewise, a function that does not have a deleted
definition shall not override a function with a deleted definition.

One would assume that a similar kind of prohibition is needed for
deallocation functions in a class hierarchy with virtual destructors,
but it's not clear that the current specification says that.
8.4 [dcl.fct.def] paragraph 10 says,

A program that refers to a deleted function implicitly or explicitly,
other than to declare it, is ill-formed.

Furthermore, the deallocation function is looked up at the point
of definition of a virtual destructor (12.4 [class.dtor]
paragraph 11), and the function found by this lookup is considered
to be “used” (3.2 [basic.def.odr] paragraph 2).
However, it's not completely clear that this “use”
constitutes a “reference” in the sense of
8.4 [dcl.fct.def] paragraph 10, especially in a program in
which an object of a type that would call that deallocation function
is never deleted.

Suggested resolution:

Augment the list of lookup results from a virtual destructor that
render a program ill-formed in 12.4 [class.dtor] paragraph 10
to include a deleted function:

If the result of this lookup is ambiguous or inaccessible, or if the
lookup selects a placement deallocation function or a function with
a deleted definition (8.4 [dcl.fct.def]), the program is
ill-formed.

Proposed resolution (June, 2008):

Change 12.4 [class.dtor] paragraph 10 as follows:

If the result of this lookup is ambiguous or inaccessible, or if the
lookup selects a placement deallocation function or a function with
a deleted definition (8.4 [dcl.fct.def]), the program is
ill-formed.

510.
Default initialization of POD classes?

8.5 [dcl.init] paragraph 10 makes it clear that
non-static POD class objects with no initializer are left uninitialized
and have an indeterminate initial value:

If no initializer is specified for an object, and the object is of
(possibly cv-qualified) non-POD class type (or array thereof), the
object shall be default-initialized; if the object is of
const-qualified type, the underlying class type shall have a
user-declared default constructor. Otherwise, if no initializer is
specified for a non-static object, the object and its subobjects, if
any, have an indeterminate initial value; if the object or any of
its subobjects are of const-qualified type, the program is ill-formed.

12.6 [class.init] paragraph 1, however, implies that all
class objects without initializers, whether POD or not, are
default-initialized:

When no initializer is specified for an object of (possibly
cv-qualified) class type (or array thereof), or the initializer has
the form (), the object is initialized as specified in
8.5 [dcl.init]. The object is default-initialized if there
is no initializer, or value-initialized if the initializer
is ().

Proposed resolution (October, 2005):

Remove the indicated words from 12.6 [class.init] paragraph 1:

When no initializer is specified for an object of (possibly
cv-qualified) class type (or array thereof), or the initializer has
the form (), the object is initialized as specified in
8.5 [dcl.init]. The object is default-initialized if
there is no initializer, or value-initialized if the initializer
is ().

683.
Requirements for trivial subobject special functions

[Voted into the WP at the September, 2008 meeting (resolution
in paper N2757).]

Part of the decision regarding whether a class has a trivial special
function (copy constructor, copy assignment operator, default constructor)
is whether its base and member subobjects have corresponding trivial
member functions. However, with the advent of defaulted functions, it is
now possible for a single class to have both trivial and nontrivial
overloads for those functions. For example,

Although B has a trivial copy constructor and thus
satisfies the requirements in 12.8 [class.copy] paragraph 6,
the copy constructor in B that would be called by the
implicitly-declared copy constructor in D is not
trivial. This could be fixed either by requiring that all the
subobject's copy constructors (or copy assignment operators, or
default constructors) be trivial or that the one that would be
selected by overload resolution be trivial.

Proposed resolution (July, 2008):

Change 8.4 [dcl.fct.def] paragraph 9 as follows:

... A special member function that would be implicitly defined as
deleted shall not be explicitly defaulted. If a special member
function for a class X is defaulted on its first declaration,
no other special member function of the same kind (default
constructor, copy constructor, or copy assignment operator) shall be
declared in class X. A special member function is
user-provided...

Notes from the September, 2008 meeting:

The resolution adopted as part of paper N2757 differs from the
July, 2008 proposed resolution by allowing defaulted and
user-provided special member functions to coexist. Instead, a
trivial class is defined as having no non-trivial copy constructors
or copy assignment operators, and a trivial copy constructor or
assignment operator is defined as invoking only trivial copy
operations for base and member subobjects.

162.
(&C::f)() with nonstatic members

13.3.1.1 [over.match.call]
paragraph 3
says that when a call of the form

(&C::f)()

is written, the set of overloaded functions named by C::f
must not contain
any nonstatic member functions. A footnote gives the rationale: if a member
of C::f is a nonstatic member function,
&C::f is a pointer to member
constant, and therefore the call is invalid.

This is clear, it's implementable, and it doesn't directly contradict
anything else in the standard. However, I'm not sure it's consistent
with some similar cases.

In 13.4 [over.over]
paragraph 5,
second example, it is made amply clear that when &C::f is
used as the address of a function, e.g.,

int (*pf)(int) = &C::f;

the overload set can contain both static and nonstatic member functions.
The function with the matching signature is selected, and if it is
nonstatic &C::f
is a pointer to member function, and otherwise &C::f is
a normal pointer to function.

is a valid call even if the overload set contains both static and
nonstatic member functions. Overload resolution is done, and if a
nonstatic member function is selected, an implicit this-> is added,
if that is possible.

Those paragraphs seem to suggest the general rule that you do overload
resolution first and then you interpret the construct you have
according to the function selected. The fact that there are static
and nonstatic functions in the overload set is irrelevant; it's only
necessary that the chosen function be static or nonstatic to match
the context.

Given that, I think it would be more consistent if the
(&C::f)() case
would also do overload resolution first. If a nonstatic member is
chosen, the program would be ill-formed.

Proposed resolution (04/01):

Change the indicated text in 13.3.1.1 [over.match.call]
paragraph 3:

The fourth case arises from a postfix-expression of the form
&F, where
F names a set of overloaded functions.
In the context of a function call,
the set of functions named by F shall contain only non-member
functions and static member functions. [Footnote:
If F names a non-static member function, &F
is a pointer-to-member, which cannot be used with the function call syntax.]
And in this context using &F behaves the same as using&F is treated the same as
the name F by itself.
Thus, (&F)(expression-listopt)
is simply
(F)(expression-listopt), which is
discussed in 13.3.1.1.1 [over.call.func].
If the function selected by overload resolution according to
13.3.1.1.1 [over.call.func] is
a nonstatic member function, the program is
ill-formed. [Footnote: When F is a nonstatic member
function, a reference of the form &A::F is a
pointer-to-member,
which cannot be used with the function-call syntax, and
a reference of the form &F is an invalid use of the
"&" operator on a nonstatic member function.]
(The resolution of &F in other contexts is described in
13.4 [over.over].)

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 a block-scope function declaration
that is not a using-declaration, the associated namespaces
and classes are not considered.

Mark Mitchell:
It looks to me like G++ is correct, given 13.3.1.1.1 [over.call.func].
This case is the "unqualified function call" case described in paragraph
3 of that section. ("Unqualified" here means that there is no "x->" or
"x." in front of the call, not that the name is unqualified.)

That paragraph says that you first do name lookup. It then asks you
to look at what declaration is returned. (That's a bit confusing; you
presumably get a set of declarations. Or maybe not; the name lookup
section says that if name lookup finds a non-static member in a context
like this the program is in error. But surely this program is not
erroneous. Hmm.)

Anyhow, you have -- at least -- "S::f(char)" as the result of the
lookup.

The keyword "this" is not in scope, so "all overloaded declarations of
the function name in T become candidate functions and a contrived object
of type T becomes the implied object argument." That means we get
both versions of "f" at this point. Then, "the call is ill-formed,
however, if overload resolution selects one of the non-static members
of T in this case." Since, in this case, "S::f(char)" is the winner,
the program is ill-formed.

Steve Adamczyk:
This result is surprising, because we've selected a function
that we cannot call, when there is another function that can be
called. This should either be ambiguous, or it should select the static
member function. See also 13.3.1 [over.match.funcs] paragraph 2:
"Similarly, when
appropriate, the context can construct an argument list that
contains an implied object argument..."

Notes from October 2002 meeting:

We agreed that g++ has it right, but the standard needs to be clearer.

Proposed resolution (October 2002, revised April 2003):

Change 13.3.1.1.1 [over.call.func] paragraphs 2 and 3 as
follows:

In qualified function calls, the name to be resolved is an
id-expression and is preceded by an -> or .
operator. Since the construct A->B is generally equivalent
to (*A).B, the rest of clause 13 [over]
assumes, without loss of generality, that all member function calls have been
normalized to the form that uses an object and the . operator.
Furthermore, clause 13 [over]
assumes that the postfix-expression that is the left
operand of the . operator has type ``cvT''
where T denotes a class.
[Footnote: Note that cv-qualifiers on the type of
objects are significant in overload resolution for both lvalue and
class rvalue objects. --- end footnote]
Under this assumption, the id-expression in the
call is looked up as a member function of T following the rules for
looking up names in classes (10.2 [class.member.lookup]).
If a member function is found, that function and its overloaded
declarationsThe function declarations found by that lookup
constitute the set of candidate functions. The argument list is the
expression-list in the call augmented by the addition of the
left operand of the . operator in the normalized member
function call as the implied object argument (13.3.1 [over.match.funcs]).

In unqualified function calls, the name is
not qualified by an -> or . operator and has the more
general form of a primary-expression. The name is looked up in the
context of the function call following the normal rules for name lookup in
function calls (3.4.2 [basic.lookup.argdep]
3.4 [basic.lookup]).
If the name resolves to a non-member function declaration, that
function and its overloaded declarationsThe function declarations found by that lookup
constitute the set of candidate functions.
[Footnote: Because of the usual name hiding rules,
these will be introduced by declarations or by using-directives all
found in the same block or all found at namespace scope. --- end footnote]Because of the rules for name lookup,
the set of candidate functions consists (1) entirely of non-member functions
or (2) entirely of member functions of some class T. In
case (1), tThe argument list is the same as
the expression-list in the call.
If the name resolves to a nonstatic member function, then the
function call is actually a member function call.In case (2), the argument list is the expression-list in the
call augmented by the addition of an implied object argument as in
a qualified function call.
If the keyword this (9.3.2 [class.this])
is in scope and refers to the class Tof that member
function, or a derived class thereofof T, then
the function call is transformed into a normalized qualified
function call usingimplied object argument is(*this)as the
postfix-expression
to the left of the . operator. The candidate
functions and argument list are as described for qualified function calls
above. If the keyword this is not in scope or refers to
another class, then name resolution found a static member of some
class T.
In this case,all overloaded declarations of the function name in
T become candidate functions and a contrived object of
type T becomes the implied object argument.
[Footnote: An implied object argument must be
contrived to correspond to the implicit object parameter attributed to member
functions during overload resolution. It is not used in the call to the
selected function. Since the member functions all have the same implicit
object
parameter, the contrived object will not be the cause to select or reject a
function. --- end footnote]
If the argument list is augmented by a contrived object
and The call is ill-formed, however, if overload
resolution selects one of the non-static member functions of
T, the
call is ill-formed in this case.

280.
Access and surrogate call functions

According to 13.3.1.1.2 [over.call.object] paragraph 2, when
the primary-expressionE in the function call syntax
evaluates to a class object of type "cvT", a
surrogate call function corresponding to an appropriate conversion
function declared in a direct or indirect base class B of
T is included or not included in the set of candidate
functions based on class B being accessible.

For instance in the following code sample, as per the paragraph in
question, the expression c(3) calls f2, instead of
the construct being ill-formed due to the conversion function
A::operator fp1 being inaccessible and its corresponding
surrogate call function providing a better match than the surrogate
call function corresponding to C::operator fp2:

The fact that the accessibility of a base class influences the
overload resolution process contradicts the fundamental language rule
(3.4 [basic.lookup] paragraph 1, and 13.3 [over.match] paragraph 2) that access checks are applied only once
name lookup and function overload resolution (if applicable) have
succeeded.

Notes from 4/02 meeting:

There was some concern about whether 10.2 [class.member.lookup] (or
anything else, for that matter) actually defines "ambiguous base class".
See issue 39. See also
issue 156.

Notes from October 2002 meeting:

It was suggested that the ambiguity check is done as part of the
call of the conversion function.

Proposed resolution (revised October 2002):

In 13.3.1.1.2 [over.call.object] paragraph 2, replace the
last sentence

Similarly, surrogate call functions are added to the set of candidate
functions for each conversion function declared in an accessible base
class provided the function is not hidden within T by another
intervening declaration.

with

Similarly, surrogate call functions are added to the set of candidate
functions for each conversion function declared in a base class of
T provided the function is not hidden within T by
another intervening declaration.

Replace 13.3.1.1.2 [over.call.object] paragraph 3

If such a surrogate call function is selected by overload resolution,
its body, as defined above, will be executed to convert E to the
appropriate function and then to invoke that function with the
arguments of the call.

by

If such a surrogate call function is selected by overload resolution,
the corresponding conversion function will be called to convert
E to the appropriate function pointer or reference,
and the function will then be invoked with the arguments of the call.
If the conversion function cannot be called
(e.g., because of an ambiguity), the program is ill-formed.

required to be diagnosed because of the op<<? The reason
being that the class may actually have an op<<(const char *) in it.

What is it? un- or ill-something? Diagnosable? No problem at all?

Steve Adamczyk:
I don't know of any requirement in the standard that the class be complete.
There is a rule that will instantiate a class template in order to be able
to see whether it has any operators. But I wouldn't think one wants to
outlaw the above example merely because the user might have an
operator<<
in the class; if he doesn't, he would not be pleased that the above
is considered invalid.

Mike Miller:
Hmm, interesting question. My initial reaction is that it just
uses ::operator<<; any A::operator<<
simply won't be considered in
overload resolution. I can't find anything in the Standard that
would say any different.

The closest analogy to this situation, I'd guess, would be
deleting a pointer to an incomplete class;
5.3.5 [expr.delete] paragraph 5 says that that's
undefined behavior if the complete type has a non-trivial destructor
or an operator delete. However, I tend to think that that's because
it deals with storage and resource management, not just because it
might have called a different function. Generally, overload
resolution that goes one way when it might have gone another with
more declarations in scope is considered to be not an error, cf
7.3.3 [namespace.udecl] paragraph 9,
14.6.3 [temp.nondep] paragraph 1, etc.

So my bottom line take on it would be that it's okay, it's up to
the programmer to ensure that all necessary declarations are in
scope for overload resolution. Worst case, it would be like the
operator delete in an incomplete class -- undefined behavior, and
thus not required to be diagnosed.

13.3.1.2 [over.match.oper] paragraph 3, bullet 1, says,
"If T1 is a class type, the set of member candidates is the result
of the qualified lookup of T1::operator@
(13.3.1.1.1 [over.call.func])." Obviously, that lookup is
not possible if T1 is
incomplete. Should
13.3.1.2 [over.match.oper] paragraph 3, bullet 1, say
"complete class type"? Or does the inability to perform
the lookup mean that the program is ill-formed?
3.2 [basic.def.odr] paragraph 4 doesn't apply,
I don't think, because you don't know whether you'll be applying a
class member access operator until you know whether the operator
involved is a member or not.