我有以下代码,基本上是
class foo {
public:
void method();
};
void foo::foo::method() { }
我不小心在foo :: method的定义前添加了一个额外的foo ::。这段代码在没有使用g ++(版本4.2.3)的情况下编译,但是使用Visual Studio 2005进行了编译。我没有名为foo的命名空间。
哪种编译器正确?
答案 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 ++允许这样做。