Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different output on different compilers

Tags:

c++

Why does the following code prints different results on different compilers?

#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();
}

Output

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

Who is right? And why is it so?

like image 833
FrozenHeart Avatar asked Jun 11 '26 04:06

FrozenHeart


1 Answers

I think gcc is right:

7.3.1.2/3 in C++11:

If a friend declaration in a non- local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition

C++03 has similar language in the same place.

I'm not sure why MSVC-11 fails to find ::foo, but I suppose you could read this text to mean that the name foo can't be looked up at all. I think the intended meaning is that the name in the innermost enclosing namespace can't be found, but the identically-spelled name in the outer scope can. But if Microsoft wants to argue the intended meaning I'm not the person they'd argue it with.

MSVC-10 is wrong, because it found a name that the standard specifically says is not found. So the explanation for the MSVC-11 behavior might be as simple as "it was reported as a bug in 10, they tried to fix it and went too far".

Anyway, the fix is to introduce a declaration of foo in 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(); }
}

This makes gcc find the friend function. I haven't tested on any version of MSVC.

like image 124
Steve Jessop Avatar answered Jun 14 '26 06:06

Steve Jessop



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!