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

2024-10-26


1111. Remove dual-scope lookup of member template names

Section: _N4868_.6.5.6  [basic.lookup.classref]     Status: C++11     Submitter: US     Date: 2010-08-02

[Voted into the WP at the March, 2011 meeting.]

N3092 comment US 23

According to _N4868_.6.5.6 [basic.lookup.classref] paragraph 1,

In a class member access expression (7.6.1.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 (13.3 [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 template. If the lookup in the class of the object expression finds a template, the name is also looked up in the context of the entire postfix-expression and

This makes the following ill-formed:

    #include <set>
    using std::set;
    struct X {
      template <typename T> void set(const T& value);
    };
    void foo() {
      X x;
      x.set<double>(3.2);
    }

That's confusing and unnecessary. The compiler has already done the lookup in X's scope, and the obviously-correct resolution is that one, not the identifier from the postfix-expression's scope. Issue 305 fixed a similar issue for destructor names but missed member functions.

Suggested resolution: Delete the end of paragraph 1, starting with “If the lookup in the class...” and including all three bullets.

Proposed resolution (November, 2010):

  1. Change 6.5.5.2 [class.qual] bullet 1.2 as follows:

  2. Change _N4868_.6.5.6 [basic.lookup.classref] paragraph 1 as follows:

  3. In a class member access expression (7.6.1.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 (13.3 [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 template. If the lookup in the class of the object expression finds a template, the name is also looked up in the context of the entire postfix-expression and

  4. Change _N4868_.6.5.6 [basic.lookup.classref] paragraph 4 as follows:

  5. If the id-expression in a class member access is a qualified-id of the form

        class-name-or-namespace-name::...
    

    the class-name-or-namespace-name following the . or -> operator is looked up both in the context of the entire postfix-expression and in the scope of the class of the object expression. If the name is found only in the scope of the class of the object expression, the name shall refer to a class-name. If the name is found only in the context of the entire postfix-expression, the name shall refer to a class-name or namespace-name. If the name is found in both contexts, the class-name-or-namespace-name shall refer to the same entity. first looked up in the class of the object expression and the name, if found, is used. Otherwise it is looked up in the context of the entire postfix-expression. [Note: See 6.5.5 [basic.lookup.qual], which describes the lookup of a name before ::, which will only find a type or namespace name. —end note]

  6. Change _N4868_.6.5.6 [basic.lookup.classref] paragraph 7 as follows:

  7. If the id-expression is a conversion-function-id, its conversion-type-id shall denote the same type in both the context in which the entire postfix-expression occurs and in the context of the class of the object expression (or the class pointed to by the pointer expression). is first looked up in the class of the object expression and the name, if found and denotes a type, is used. Otherwise it is looked up in the context of the entire postfix-expression and the name shall denote a type. [Example:

      struct A { };
      namespace N {
        struct A {
          void g() { }
          template <class T> operator T();
        };
      }
    
      int main() {
        N::A a;
        a.operator A();    // calls N::A::operator N::A
      }
    

    end example]