【问题标题】:template class in enclosing namespace as friend封闭命名空间中的模板类作为朋友
【发布时间】:2013-04-02 17:30:35
【问题描述】:

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

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

template<typename> friend class my::A;

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

【问题讨论】:

  • 甚至认为这个问题有点老了:没有类的前向声明。您要么声明它们,如 template&lt;typename&gt; class A 所述,要么提供类定义 class Foo {...}
  • @SebTu 没有定义的声明(无论什么)通常称为forward declaration。这可以是函数、类或模板。

标签: c++ templates namespaces clang friend


【解决方案1】:

我认为 Clang 是对的:

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

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

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

【讨论】:

  • 嗯。 // ::h not considered 与我的情况无关,因为这是一个简单的非模板独立方法,而不是模板类。 template-idelaborated-type-specifier 到底是什么??
  • A template-id 是示例中的f2&lt;&gt;,它总是有尖括号。 elaborated-type-specifier 就是您的示例的情况,上面说“函数或 elaborated-type-specifier”,它在第 7.1.6.3 节中定义。
  • 好的,谢谢。我在gcc.gnu.org/bugzilla/show_bug.cgi?id=56820 向 gcc 提交了错误报告
  • @Walter btw 我用g++ 5.4.0编译了来自错误报告的源附件:仍然没有产生所需的警告。我对修复编译器错误的过程不太熟悉,但不应该期望它在 3 年后更新/解决吗?
  • @SebTu 不一定。这当然是低优先级,bugzilla 说它还没有被修复,甚至没有分配给任何人,也没有成为目标......
猜你喜欢
  • 2018-10-20
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多