2012-12-18 37 views
3

为什么下面的代码在不同的编译器上输出不同的结果?不同编译器上的输出不同

#include <iostream> 

void foo() { std::cout << "::foo() \n"; } 

namespace Foo 
{ 
    struct Bar 
    { 
     friend void foo() { std::cout << "Bar::foo() \n"; } 
     void bar() { foo(); } 
     void baz(); 
    }; 

    void Bar::baz() { foo(); } 
} 

int main() 
{ 
    Foo::Bar instance; 
    instance.bar(); 
    instance.baz(); 
} 

输出

GCC 4.7.2

::foo() 
::foo() 

MSVC-10.0

Bar::foo() 
Bar::foo() 

MSVC-11.0

error C3861: 'foo': identifier not found 
error C3861: 'foo': identifier not found 

谁是谁非?为什么这样呢?

+0

顺便说一句,你打印'Bar :: foo',但是定义的函数有'Foo :: foo'。它是'Foo'命名空间中的一个自由函数,不是'Bar'的成员。 –

+0

@Steve Jessop哦,是的,谢谢。但是,这不是我的问题 – FrozenHeart

回答

2

我认为GCC是正确的:

7.3.1.2/3在C++ 11:

如果非本地 类第一个朋友声明声明一个类或函数朋友类或 函数是最内层封闭名称空间的成员。的 朋友的名字没有被unquali网络版查找(3.4.1),或者通过合格网络发现编 查找(3.4.3),直到匹配的声明在 命名空间内提供(无论是前或班德网络nition

C++ 03有在同一个地方类似的语言。

我不知道为什么MSVC-11无法找到::foo,但我想你可能阅读这段文字的意思,这个名字foo可以”我认为其意图是不能找到最内层的名字空间中的名字,但是外部范围中拼写相同的名称可以。但是,如果微软想要争辩意图的含义,我不是他们与之争论的人。

MSVC-10是错误的,因为它找到了标准没有找到的名称。因此,对于MSVC-11行为的解释可能很简单,就像“它被报告为10中的一个错误,他们试图修复它并且过分执行”。

无论如何,解决方法是在命名空间Foo介绍foo声明:

namespace Foo 
{ 
    void foo(); // this is a matching declaration 
    struct Bar 
    { 
     friend void foo() { std::cout << "Bar::foo() \n"; } 
     void bar() { foo(); } 
     void baz(); 
    }; 

    void Bar::baz() { foo(); } 
} 

这使得GCC找到友元函数。我没有在任何版本的MSVC上进行测试。

+0

所以,我怎么能在这种情况下调用朋友功能? – FrozenHeart

+0

@Nikita:在类定义之前的命名空间范围内放置一个匹配声明。还要注意,AFAIK这样的朋友函数*可以通过ADL找到(也就是说,如果它有任何相关的参数的话),这就是为什么你不需要将操作符重载与定义分开声明为朋友的原因。 –

+0

我说“AFAIK”ADL发现它:这是我引用的第二个句子:-) –

相关问题