3

我的代码具有以下基本结构

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

它在 gcc(4.7 和 4.8,using -std=c++11)和 icpc(13.1)下编译得很好,但不是 clang(using -std=c++11 -stdlib=libc++),它抱怨使用了非公共构造函数(在实例化有问题的方法时)。事实证明,如果朋友声明给出了完整的限定名,clang 很高兴,如

template<typename> friend class my::A;

这是clang的错误吗?我原以为封闭命名空间中的任何可见符号都可以在内部命名空间my中使用,而无需进一步限定my::details。2011 年标准怎么说?

4

1 回答 1

4

我认为 Clang 是对的:

7.3.1.2 命名空间成员定义[namespace.memdef]

3在命名空间中首先声明的每个名称都是该命名空间的成员。如果friend非本地类中的声明首先声明了类、函数、类模板或函数模板,则友元是最内层封闭命名空间的成员。在该命名空间范围内(在授予友谊的类定义之前或之后)提供匹配声明之前,未限定查找 (3.4.1) 或限定查找 (3.4.3) 无法找到朋友的名称。如果调用友元函数或函数模板,则可以通过名称查找找到其名称,该名称查找考虑来自与函数参数类型相关联的命名空间和类的函数(3.4.2)。如果friend声明中的名称既不是限定的也不是模板 ID并且声明是函数或详细类型说明符确定实体是否先前已声明的查找不应考虑最内层封闭命名空间之外的任何范围。[注意:其他形式的友元声明不能声明最内层封闭命名空间的新成员,因此遵循通常的查找规则。—尾注] [示例:

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

结束示例]

注意// ::h not considered.

于 2013-04-02T17:39:24.323 回答