14 Templates [temp]

14.5 Template declarations [temp.decls]

14.5.4 Friends [temp.friend]

A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or a non-template function or class. For a friend function declaration that is not a template declaration:

  • if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise,

  • if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace, the friend declaration refers to that function, otherwise,

  • if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template ([temp.deduct.decl]), otherwise,

  • the name shall be an unqualified-id that declares (or redeclares) a non-template function.

Example:

template<class T> class task;
template<class T> task<T>* preempt(task<T>*);

template<class T> class task {
  friend void next_time();
  friend void process(task<T>*);
  friend task<T>* preempt<T>(task<T>*);
  template<class C> friend int func(C);

  friend class task<int>;
  template<class P> friend class frd;
};

Here, each specialization of the task class template has the function next_time as a friend; because process does not have explicit template-arguments, each specialization of the task class template has an appropriately typed function process as a friend, and this friend is not a function template specialization; because the friend preempt has an explicit template-argument T, each specialization of the task class template has the appropriate specialization of the function template preempt as a friend; and each specialization of the task class template has all specializations of the function template func as friends. Similarly, each specialization of the task class template has the class template specialization task<int> as a friend, and has all specializations of the class template frd as friends.  — end example ]

A friend template may be declared within a class or class template. A friend function template may be defined within a class or class template, but a friend class template may not be defined in a class or class template. In these cases, all specializations of the friend class or friend function template are friends of the class or class template granting friendship. [ Example:

class A {
  template<class T> friend class B;                 // OK
  template<class T> friend void f(T){ /* ... */ }  // OK
};

 — end example ]

A template friend declaration specifies that all specializations of that template, whether they are implicitly instantiated ([temp.inst]), partially specialized ([temp.class.spec]) or explicitly specialized ([temp.expl.spec]), are friends of the class containing the template friend declaration. [ Example:

class X {
  template<class T> friend struct A;
  class Y { };
};

template<class T> struct A { X::Y ab; };            // OK
template<class T> struct A<T*> { X::Y ab; };        // OK

 — end example ]

When a function is defined in a friend function declaration in a class template, the function is instantiated when the function is odr-used ([basic.def.odr]). The same restrictions on multiple declarations and definitions that apply to non-template function declarations and definitions also apply to these implicit definitions.

A member of a class template may be declared to be a friend of a non-template class. In this case, the corresponding member of every specialization of the class template is a friend of the class granting friendship. For explicit specializations the corresponding member is the member (if any) that has the same name, kind (type, function, class template, or function template), template parameters, and signature as the member of the class template instantiation that would otherwise have been generated. [ Example:

template<class T> struct A {
  struct B { };
  void f();
  struct D {
    void g();
  };
};
template<> struct A<int> {
  struct B { };
  int f();
  struct D {
    void g();
  };
};

class C {
  template<class T> friend struct A<T>::B;    // grants friendship to A<int>::B even though
                                              // it is not a specialization of A<T>::B
  template<class T> friend void A<T>::f();    // does not grant friendship to A<int>::f()
                                              // because its return type does not match
  template<class T> friend void A<T>::D::g(); // does not grant friendship to A<int>::D::g()
                                              // because A<int>::D is not a specialization of A<T>::D
};

 — end example ]

Note: A friend declaration may first declare a member of an enclosing namespace scope ([temp.inject]).  — end note ]

A friend template shall not be declared in a local class.

Friend declarations shall not declare partial specializations. [ Example:

template<class T> class A { };
class X {
  template<class T> friend class A<T*>; // error
};

 — end example ]

When a friend declaration refers to a specialization of a function template, the function parameter declarations shall not include default arguments, nor shall the inline specifier be used in such a declaration.