Title
Friend declarations of template-ids
Status
tc1
Section
10.3.1.2 [namespace.memdef]
Submitter
John Spicer

Created on 1999-09-08.00:00:00 last changed 208 months ago

Messages

Date: 2000-10-15.00:00:00

Proposed resolution (10/00):

In 10.3.1.2 [namespace.memdef] paragraph 3, change

When looking for a prior declaration of a class or a function declared as a friend, scopes outside the innermost enclosing namespace scope are not considered.
to
When looking for a prior declaration of a class or a function declared as a friend, and when the name of the friend class or function is neither a qualified name nor a template-id, scopes outside the innermost enclosing namespace scope are not considered.
Also, change the example in that paragraph as follows:
    void h(int);
    template <class T> void f2(T);
    namespace A {
        class X {
            friend void f(X);       // A::f(X) is a friend
            friend void f2<>(int);  // ::f2<>(int) is a friend
    ...

(See also issues 95, 136, 138, 139, 143, and 165.)

Date: 2004-09-10.00:00:00

John Spicer: I believe the standard is not clear with respect to this example:

    namespace N {
      template <class T> void f(T);
      namespace M {
        struct A {
          friend void f<int>(int);  // okay - refers to N::f
        };
      }
    }
At issue is whether the friend declaration refers to N::f, or whether it is invalid.

A note in 6.3.2 [basic.scope.pdecl] paragraph 6 says

friend declarations refer to functions or classes that are members of the nearest enclosing namespace ...
I believe it is intended to mean unqualified friend declarations. Certainly friend void A::B() need not refer to a member of the nearest enclosing namespace. Only when the declarator is unqualified (i.e., it is a declaration and not a reference) does this rule need to apply. The presence of an explicit template argument list requires that a previous declaration be visible and renders this a reference and not a declaration that is subject to this rule.

Mike Miller: 10.3.1.2 [namespace.memdef] paragraph 3 says,

When looking for a prior declaration of a class or a function declared as a friend, scopes outside the innermost enclosing namespace scope are not considered.
On the other hand, the friend declaration would be a syntax error if f weren't declared as a template name; it would seem very strange not to find the declaration that made the friend declaration syntactically correct. However, it also seems strange to treat this case differently from ordinary functions and from templates:
    namespace N {
      template <class T> void f(T);
      void g();
      namespace M {
        struct A {
          friend void f<int>(int);               // N::f
          template <class T> friend void f(T);   // M::f
          friend void g();                       // M::g
        };
      }
    }

John Spicer: This section refers to "looking for a prior declaration". This gets back to an earlier discussion we've had about the difference between matching two declarations of the same name and doing name lookup. I would maintain that in f<int> the f is looked up using a normal lookup. In practice, this is really how it has to be done because the declaration could actually be f<int>::x.

History
Date User Action Args
2003-04-25 00:00:00adminsetstatus: dr -> tc1
2000-11-18 00:00:00adminsetstatus: ready -> dr
2000-05-21 00:00:00adminsetstatus: review -> ready
2000-02-23 00:00:00adminsetmessages: + msg222
2000-02-23 00:00:00adminsetstatus: open -> review
1999-09-08 00:00:00admincreate