为什么 gcc 无法从其前向声明中检测到友元类命名空间?

Gup*_*pta 3 c++ namespaces friend language-lawyer c++11

我有以下代码可以用 VS2015 编译,但不能用 gcc(任何版本)编译。对我来说,的命名空间class A_Creator是正确定义的(即根命名空间),因为 is 已经在程序顶部进行了前向声明。为什么 gcc 无法A_Creator正确检测类的命名空间?哪个编译器是对的?

#include <list>

class A_Creator;

namespace X
{
class A
{
private:
   int mX;

   A(int x) :
      mX(x)
   {}

   // GCC complains about this line, and it should be changed to ::A_Creator
   // On VS2015, both of them are working
   friend class A_Creator; 
};

} // namespace X

class A_Creator
{
public:

   std::list<X::A> TestOnList(int z)
   {
      std::list<X::A> a_list;
      a_list.push_back(X::A(z));

      return a_list;
   }
};


int main()
{
   A_Creator a_cr;
   auto x = a_cr.TestOnList(12);
}
Run Code Online (Sandbox Code Playgroud)

Lan*_*yer 5

C++11 [namespace.memdef]/3

如果friend声明中的名称既不是限定名也不是模板 id并且声明是函数或详细类型说明符,则确定实体是否已被先前声明的查找不应考虑最内部封闭命名空间之外的任何范围。[注意:其他形式的朋友声明不能声明最内部封闭命名空间的新成员,因此遵循通常的查找规则。— 尾注]

由于您在friend声明 ( friend class A_Creator;) 中有详细说明的类型说明符,因此只能在最内部的封闭命名空间中搜索先前的声明::X。所以,gcc 是对的。
[namespace.memdef]/3 中示例的相关摘录,带有函数而不是类的全局前向声明:

void h(int);
namespace A {
  class X {
    class Y {
      friend void h(int);       // A::h is a friend
                                // ::h not considered
    };
  };
}
Run Code Online (Sandbox Code Playgroud)