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


490. Name lookup in friend declarations

Section: 6.5.3  [basic.lookup.unqual]     Status: CD2     Submitter: Ben Hutchings     Date: 7 Dec 2004

[Voted into WP at March, 2010 meeting.]

When 6.5.3 [basic.lookup.unqual] paragraph 10 says,

In a friend declaration naming a member function, a name used in the function declarator and not part of a template-argument in a template-id is first looked up in the scope of the member function's class. If it is not found, or if the name is part of a template-argument in a template-id, the look up is as described for unqualified names in the definition of the class granting friendship.

what does “in the scope of the member function's class” mean? Does it mean that only members of the class and its base classes are considered? Or does it mean that the same lookup is to be performed as if the name appeared in the member function's class? Implementations vary in this regard. For example:

     struct s1;

     namespace ns {
         struct s1;
     }

     struct s2 {
         void f(s1 &);
     };

     namespace ns {
         struct s3 {
             friend void s2::f(s1 &);
         };
     }

Microsoft Visual C++ and Comeau C++ resolve s1 in the friend declaration to ns::s1 and issue an error, while g++ resolves it to ::s1 and accepts the code.

Notes from the April, 2005 meeting:

The phrase “looked up in the scope of [a] class” occurs frequently throughout the Standard and always refers to the member name lookup described in 6.5.2 [class.member.lookup]. This is the first interpretation mentioned above (“only members of the class and its base classes”), resolving s1 to ns::s1. A cross-reference to 6.5.2 [class.member.lookup] will be added to 6.5.3 [basic.lookup.unqual] paragraph 10 to make this clearer.

In discussing this question, the CWG noticed another problem: the text quoted above applies to all template-arguments appearing in the function declarator. The intention of this rule, however, is that only template-arguments in the declarator-id should ignore the member function's class scope; template-arguments used elsewhere in the function declarator should be treated like other names. For example:

     template<typename T> struct S;
     struct A {
       typedef int T;
       void foo(S<T>);
     };
     template <typename T> struct B {
       friend void A::foo(S<T>);  // i.e., S<A::T>
     };

Proposed resolution (February, 2010):

Change 6.5.3 [basic.lookup.unqual] paragraph 10 as follows:

In a friend declaration naming a member function, a name used in the function declarator and not part of a template-argument in a template-id the declarator-id is first looked up in the scope of the member function's class (6.5.2 [class.member.lookup]). If it is not found, or if the name is part of a template-argument in a template-id the declarator-id, the look up is as described for unqualified names in the definition of the class granting friendship. [Example:

    struct A {
      typedef int AT;
      void f1(AT);
      void f2(float);
      template<typename T> void f3();
    };
    struct B {
      typedef char AT;
      typedef float BT;
      friend void A::f1(AT);    // parameter type is A::AT
      friend void A::f2(BT);    // parameter type is B::BT
      friend void A::f3<AT>();  // template argument is B::AT
    };

end example]