简体   繁体   中英

template class in enclosing namespace as friend

I have code with the following basic structure

namespace my {
  template<typename> class A;              // forward declaration
  namespace details {
    template<typename T> class B
    {
      const T*const t;
      B(const T*x) : t(x) {}               // non-public constructor
      template<typename> friend class A;   // friend declaration
    };
  }
  template<typename T> class A
  {
    T*const t;
  public:
    A(T*x) : t(x) {}
    details::B<T> makeb() const            // offending method:
    { return details::B<T>(t); }           //   calls non-public constructor
  };
}

which compiled fine under gcc (4.7 & 4.8, using -std=c++11 ) and icpc (13.1), but not clang (using -std=c++11 -stdlib=libc++ ), which complains about usage of a non-public constructor (when instantinating the offending method). It turns out that clang is happy if the friend declaration gives the full qualified name, as in

template<typename> friend class my::A;

Is this a bug of clang? I would have thought that any visible symbol in the enclosing namespace my is available without further qualification in the inner namespace my::details . What does the 2011 standard say?

I think Clang is right:

7.3.1.2 Namespace member definitions [namespace.memdef]

3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). If a friend function or function template is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier , the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace . [ Note: The other forms of friend declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual lookup rules. end note ] [ Example:

// Assume f and g have not yet been declared.
void h(int);
template <class T> void f2(T);
namespace A {
  class X {
    friend void f(X);         // A::f(X) is a friend
    class Y {
      friend void g();        // A::g is a friend
      friend void h(int);     // A::h is a friend
                              // ::h not considered
      friend void f2<>(int);  // ::f2<>(int) is a friend
    };
  };

  // A::f, A::g and A::h are not visible here
  X x;
  void g() { f(x); }          // definition of A::g 
  void f(X) { /* ...  */}     // definition of A::f 
  void h(int) { /* ...  */ }  // definition of A::h
  // A::f, A::g and A::h are visible here and known to be friends
}

using A::x;

void h() {
  A::f(x);
  A::X::f(x);      // error: f is not a member of A::X
  A::X::Y::g();    // error: g is not a member of A::X::Y
}

end example ]

Note the // ::h not considered .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM