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

2024-04-18


147. Naming the constructor

Section: _N4567_.5.1.1  [expr.prim.general]     Status: TC1     Submitter: John Spicer     Date: 21 Feb 1999

From paper J16/99-0010 = WG21 N1187.

_N4567_.5.1.1 [expr.prim.general] paragraph 7 says that class-name::class-name names the constructor when both class-name refer to the same class. (Note the different perspective, at least, in 11.4.5 [class.ctor] paragraph 1, in which constructors have no names and are recognized by syntactic context rather than by name.)

This formulation does not address the case of classes in which a function template is declared as a constructor, for example:

    template <class T> struct A {
        template <class T2> A(T2);
    };
    template<> template<> A<int>::A<int>(int);

Here there is an ambiguity as to whether the second template argument list is for the injected class name or for the constructor.

Suggested resolution: restate the rule as a component of name lookup. Specifically, if when doing a qualified lookup in a given class you look up a name that is the same as the name of the class, the entity found is the constructor and not the injected class name. In all other cases, the name found is the injected class name. For example:

    class B { };
    class A: public B {
        A::B ab;       // B is the inherited injected B
        A::A aa;       // Error: A::A is the constructor
    };

Without this rule some very nasty backtracking is needed. For example, if the injected class name could be qualified by its own class name, the following code would be well-formed:

    template <class T> struct A {
        template <class T2> A(T2);
        static A x;
    };
    template<> A<int>::A<int>(A<int>::x);

Here the declarator for the definition of the static data member has redundant parentheses, and it's only after seeing the declarator that the parser can know that the second A<int> is the injected class name rather than the constructor.

Proposed resolution (10/00):

In Clause 11 [class] paragraph 2, change

The class-name is also inserted into the scope of the class itself. For purposes of access checking the inserted class name...

to

The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name...

Also, in 6.5.5.2 [class.qual], add the following before paragraph 2:

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 11 [class]), the name is instead considered to name the constructor of class C. Such a constructor name shall only be used in the declarator-id of a constructor definition that appears outside of the class definition. [Example:
    struct A { A(); };
    struct B: public A { B(); };

    A::A() { }
    B::B() { }

    B::A ba;    // object of type A
    A::A a;     // error, A::A is not a type name
end example]

Also, change 6.5 [basic.lookup] paragraph 3 from

Because the name of a class is inserted in its class scope ( Clause 11 [class]), the name of a class is also considered a member of that class for the purposes of name hiding and lookup.

to

The injected-class-name of a class (Clause 11 [class]) is also considered to be a member of that class for the purposes of name hiding and lookup.

(See also issue 194.)