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思います。意図した意味は、最も内側の名前空間の名前は見つからないが、外側のスコープの同じスペルの名前は見つかるということだと思います。しかし、Microsoft が意図した意味について議論したい場合、私は彼らが議論するような人物ではありません。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 に答える