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

2024-11-11


638. Explicit specialization and friendship

Section: 13.7.5  [temp.friend]     Status: CD2     Submitter: Daveed Vandevoorde     Date: 6 July 2007

[Voted into WP at March, 2010 meeting.]

Is this code well-formed?

    template <typename T> struct A {
        struct B;
    };

    class C {
        template <typename T> friend struct A<T>::B;
        static int bar;
    };

    template <> struct A<char> {
        struct B {
            int f() {
                return C::bar;   // Is A<char>::B a friend of C?
            }
        };
    };

According to 13.7.5 [temp.friend] paragraph 5,

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.

This would tend to indicate that the example is well-formed. However, technically A<char>::B does not “correspond to” the same-named member of the class template: 13.9.4 [temp.expl.spec] paragraph 4 says,

The definition of an explicitly specialized class is unrelated to the definition of a generated specialization. That is, its members need not have the same names, types, etc. as the members of a generated specialization.

In other words, there are no “corresponding members” in an explicit specialization.

Is this the outcome we want for examples like the preceding? There is diversity among implementations on this question, with some accepting the example and others rejecting it as an access violation.

Notes from the July, 2009 meeting:

The consensus of the CWG was to allow the correspondence of similar members in explicit specializations.

Proposed resolution (October, 2009):

Change 13.7.5 [temp.friend] paragraph 5 as follows:

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
  };