This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 113d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-03-20


298. T::x when T is cv-qualified

Section: 6.5.5.2  [class.qual]     Status: CD1     Submitter: Steve Adamczyk     Date: 7 Jul 2001

[Voted into WP at April 2003 meeting.]

Can a typedef T to a cv-qualified class type be used in a qualified name T::x?

    struct A { static int i; };
    typedef const A CA;
    int main () {
      CA::i = 0;  // Okay?
    }

Suggested answer: Yes. All the compilers I tried accept the test case.

Proposed resolution (10/01):

In 6.5.5.2 [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 (6.5.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 (11.7 [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 9.2.4 [dcl.typedef] paragraph 4:

Argument and text removed from proposed resolution (October 2002):

9.2.4 [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 be have 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 (6.6 [basic.link]). [Example: ...

Proposed resolution (October 2002):

6.5.6 [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.

_N4567_.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 (11.3 [class.name]). Except as the identifier in the declarator for a constructor or destructor definition outside of a class member-specification (11.4.5 [class.ctor], 11.4.7 [class.dtor]), a typedef-name that names a class may be used in a qualified-id to refer to a constructor or destructor. ]

9.2.4 [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 11.3 [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 (11.3 [class.name]). If a typedef-name is used following the class-key in an elaborated-type-specifier (9.2.9.5 [dcl.type.elab]), or in the class-head of a class declaration (Clause 11 [class]), or is used as the identifier in the declarator for a constructor or destructor declaration (11.4.5 [class.ctor], 11.4.7 [class.dtor]), to identify the subject of an elaborated-type-specifier (9.2.9.5 [dcl.type.elab]), class declaration (Clause 11 [class]), constructor declaration (11.4.5 [class.ctor]), or destructor declaration (11.4.7 [class.dtor]), the program is ill-formed. ] [Example: ...

9.2.9.5 [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-name or a template type-parameter, the elaborated-type-specifier is ill-formed. [Note: ...

9.3 [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.

11.3 [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 9.2.4 [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 11.3 [class.name].")

A typedef-name (9.2.4 [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 9.2.4 [dcl.typedef]. as the identifier in a class-head.

11.4.5 [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 (9.2.4 [dcl.typedef]); however, a A typedef-name that names a class shall not be used as the identifier class-name in the declarator declarator-id for a constructor declaration.

11.4.7 [class.dtor] paragraph 1:

The same comments apply here as to 11.4.5 [class.ctor].

... A typedef-name that names a class is a class-name (7.1.3); however, a A typedef-name that names a class shall not be used as the identifier class-name following the ~ in the declarator for a destructor declaration.