这是有效的C++代码吗?

Mik*_*keT 23 c++ visual-studio-2005 g++

我有以下代码,基本上,

class foo {
  public:
    void method();
};

void foo::foo::method() { }
Run Code Online (Sandbox Code Playgroud)

我不小心在foo :: method的定义前添加了一个额外的foo ::.这段代码在没有使用g ++(版本4.2.3)的情况下编译,但是使用Visual Studio 2005进行了编译.我没有名为foo的命名空间.

哪个编译器正确?

Ale*_*ell 25

如果我正确读取标准,g ++是正确的,VS是错误的.

ISO-IEC 14882-2003(E),§9.2类(第153页):在看到类名后立即将类名插入到作用域中.类名也插入到类本身的范围内; 这被称为注入类名.出于访问检查的目的,inject-class-name被视为公共成员名称.

根据下面的评论,保留以下有关实际名称查找规则的内容也特别有用:

ISO-IEC 14882-2003(E),§3.4-3名称查找(第29页):为了名称的目的,类的注入类名(第9条)也被认为是该类的成员隐藏和查找.

如果没有,那将是奇怪的,因为9.2的文本的最后部分.但正如litb评论的那样,这让我们放心,g ++确实正在对标准做出正确的解释.没有问题.

  • 不完全,没有.可以找到我认为的描述3.4.3.1 - 限定名称查找:在将:: scope解析运算符(5.1)应用于指定其名称的嵌套名称说明符之后,可以引用类或名称空间成员的名称.类或命名空间.在查找:: scope resolution运算符之前的名称期间,将忽略对象,函数和枚举器名称.如果找到的名称不是类名(第9节)或命名空间名(7.3.1),则程序格式不正确 (2认同)
  • 另一个引用:*"类的注入类名(第9节)也被认为是该类的成员,用于名称隐藏和查找."*来自`3.4/3`.类中的查找是根据成员名称定义的 - 因此它使得引用实际上使其对问题中的案例有效.请注意,结果是错误的`struct A {void f(){A :: A a; 拒绝那个有效的代码:)如果你在答案中包含那个引用,我将+1你xD (2认同)

Ric*_*den 11

Krugar在这里有正确的答案.每次找到的名称是注入的类名.

以下是一个示例,它显示了编译器添加注入的类名称的至少一个原因:

namespace NS
{
  class B
  {
  // injected name B    // #1
  public:
    void foo ();
  };

  int i;                // #2
}

class B                 // #3
{
public:
  void foo ();
};


int i;                  // #4

class A :: NS::B
{
public:
  void bar ()
  {
    ++i;           // Lookup for 'i' searches scope of
                   // 'A', then in base 'NS::B' and
                   // finally in '::'.  Finds #4

    B & b = *this; // Lookup for 'B' searches scope of 'A'
                   // then in base 'NS::B' and finds #1
                   // the injected name 'B'.

  }
};
Run Code Online (Sandbox Code Playgroud)

如果没有注入的名称,当前的查找规则最终会到达'A'的封闭范围,并且会找到':: B'而不是'NS :: B'.因此,当我们想要引用基类时,我们需要在A中的任何地方使用"NS :: B".

注入名称的另一个地方是使用模板,在类模板中,注入的名称提供模板名称和类型之间的映射:

template <typename T>
class A
{
// First injected name 'A<T>'
// Additional injected name 'A' maps to 'A<T>'

public:
  void foo ()
  {
    // '::A' here is the template name
    // 'A' is the type 'A<T>'
    // 'A<T>' is also the type 'A<T>'
  }
};
Run Code Online (Sandbox Code Playgroud)