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

谁是对的?为什么会这样?

4

1 回答 1

2

我认为 gcc 是正确的:

C++11 中的 7.3.1.2/3:

如果非本地类中的友元声明首先声明了一个类或函数,则友元类或函数是最内层封闭命名空间的成员。在该命名空间范围内(在类定义之前或之后)提供匹配声明之前,未限定查找 (3.4.1) 或限定查找 (3.4.3) 无法找到朋友的名称

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

我不确定为什么 MSVC-11 无法找到::foo,但我想您可以阅读此文本以表示foo根本无法查找该名称。我认为预期的含义是找不到最里面的封闭命名空间中的名称,但可以找到外部范围内的同名名称。但如果微软想要争论预期的含义,我不是他们会争论的人。

MSVC-10 是错误的,因为它找到了标准明确规定的名称未找到。所以对 MSVC-11 行为的解释可能很简单,就像“它被报告为 10 中的一个错误,他们试图修复它并且走得太远了”。

无论如何,解决方法是引入fooin namespace的声明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 上测试过。

于 2012-12-18T17:30:59.973 回答