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

时间:2009-08-12 01:34:19

标签: c++ visual-studio-2005 g++

我有以下代码,基本上是

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

void foo::foo::method() { }

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

哪种编译器正确?

4 个答案:

答案 0 :(得分:25)

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

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

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

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

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

答案 1 :(得分: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'.

  }
};

如果没有注入名称,当前的查找规则最终会到达'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>'
  }
};

答案 2 :(得分:1)

Comeau online接受它没有任何关键,所以它是有效的,或者是近十年来我发现的como中的第二个错误。

答案 3 :(得分:0)

在你包含的其他模块中是否有一个名称空间foo(你只是不知道它)?否则,它是不正确的。我不确定为什么g ++允许这样做。