简体   繁体   English

为什么我不能转发声明内部朋友课程?

[英]Why can't I forward declare an internal friend class?

this code compiles under MSVC 2013, but not under Clang 500.2.79: 此代码在MSVC 2013下编译,但不在Clang 500.2.79下编译:

class A
{
    friend class B;
    B *b;
};

class B
{
};

> error: unknown type name 'B'

Why? 为什么?

A friend declaration doesn't itself (always) require a forward declaration, but subsequent uses of the friend pointers/references do. 朋友声明本身并不需要(始终)需要前向声明,但是朋友指针/引用的后续使用却需要。 VC++ appears to be allowing functionality not allowed by the language specification. VC ++似乎允许使用语言规范所不允许的功能。 Functions do have slightly more liberal lookup rules than classes though: 函数确实比类具有更自由的查找规则:

C++11 §7.3.1.2/3 (Namespace member definitions) [namespace.memdef] : C ++ 11§7.3.1.2/ 3 (名称空间成员定义) [namespace.memdef]

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). 直到通过在名称空间范围中提供匹配的声明(在授予友谊的类定义之前或之后),才可以通过不合格的查找(3.4.1)或合格的查找(3.4.3)找不到朋友的名称。 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). 如果调用了朋友函数或函数模板 ,则可以通过名称查找来找到其名称,该名称查找考虑了来自与函数参数类型相关联的名称空间和类中的函数(3.4.2)。

The specification's 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
}

Internal ("nested") classes are automatically friended, but they have to be defined, not just declared, internally: 内部(“嵌套”)类会自动成为好友,但必须在内部定义它们,而不只是声明它们:

class A {
  public:
    // This class is nested, and referred to as "A::B" outside of A.
    class B {
      public:
        int foo(A &a) { return a.x; } // OK by default to access A's privates
    };

  private:
    int x;
};

A a;
A::B b;
int n = b.foo(a);

If you move your definition of B (or just make a forward declaration), you can properly friend a non-nested class: 如果您移动B的定义(或只是进行前向声明),则可以适当地将一个非嵌套类作为朋友:

class B;

class A {
  friend class B; // OK, since B (not nested) declared before this directive
  B *b; 
}

class B { }; // can define B later, since only B pointer/references used earlier

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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