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-04-05


1988. Ambiguity between dependent and non-dependent bases in implicit member access

Section: 13.8.3.2  [temp.dep.type]     Status: CD4     Submitter: Richard Smith     Date: 2014-08-22

[Moved to DR at the May, 2015 meeting.]

According to 13.8.3.2 [temp.dep.type] paragraph 7,

If, for a given set of template arguments, a specialization of a template is instantiated that refers to a member of the current instantiation with a qualified-id or class member access expression, the name in the qualified-id or class member access expression is looked up in the template instantiation context. If the result of this lookup differs from the result of name lookup in the template definition context, name lookup is ambiguous. [Note: the result of name lookup differs only when the member of the current instantiation was found in a non-dependent base class of the current instantiation and a member with the same name is also introduced by the substitution for a dependent base class of the current instantiation. —end note]

It is not clear whether this applies to an example like,

   struct A { int n; };
   struct B { int n; };
   template<typename T> struct C : T, B {
     int f() { return n; }
   };
   int k = C<A>().f();

since the reference to n is transformed into a class member access expression, per 11.4.3 [class.mfct.non.static] paragraph 3.

Notes from the November, 2014 meeting:

The transformation to a member access expression or qualified-id should be performed only in the instantiated function, not when processing the template definition.

Proposed resolution (April, 2015):

  1. Change 11.4.3 [class.mfct.non.static] paragraph 3 as follows:

  2. When an id-expression (7.5 [expr.prim]) that is not part of a class member access syntax (7.6.1.5 [expr.ref]) and not used to form a pointer to member (7.6.2.2 [expr.unary.op]) is used in a member of class X in a context where this can be used (_N4567_.5.1.1 [expr.prim.general]), if name lookup (6.5 [basic.lookup]) resolves the name in the id-expression to a non-static non-type member of some class C, and if either the id-expression is potentially evaluated or C is X or a base class of X, the id-expression is transformed into a class member access expression (7.6.1.5 [expr.ref]) using (*this) (_N4868_.11.4.3.2 [class.this]) as the postfix-expression to the left of the . operator. [Note: If C is not X or a base class of X, the class member access expression is ill-formed. —end note] Similarly during name lookup, when an unqualified-id (7.5 [expr.prim]) used in the definition of a member function for class X resolves to a static member, an enumerator or a nested type of class X or of a base class of X, the unqualified-id is transformed into a qualified-id (7.5 [expr.prim]) in which the nested-name-specifier names the class of the member function. These transformations do not apply in the template definition context (13.8.3.2 [temp.dep.type]). [Example:...
  3. Change the example in 13.8.3.2 [temp.dep.type] paragraph 7, as modified by the resolution of issue 1309, as follows:

  4.   struct A {
        int m;
      };
    
      struct B {
        int m;
      };
    
      template<typename T>
      struct C : A, T {
        int f() { return this->m; }// finds A::m in the template definition context
        int g() { return m; }      // finds A::m in the template definition context
      };
    
      template int C<B>::f();      // error: finds both A::m and B::m
      template int C<B>::g();      // OK: transformation to class member access syntax
                                   // does not occur in the template definition context; see 11.4.3 [class.mfct.non.static]