3

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?

2
  • Btw, you print Bar::foo but the function being defined there is Foo::foo. It's a free function in namespace Foo, not a member of Bar. Commented Dec 18, 2012 at 17:17
  • @Steve Jessop Oh, yeah, thanks. But this is not my question anyway Commented Dec 18, 2012 at 17:18

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

So, how can i call friend function in such kind of situation?
@Nikita: put a matching declaration in namespace scope before the class definition. Also note that AFAIK such a friend function can be found by ADL (that is, it could if it had any relevant arguments), which is why you don't need to declare operator overloads separately from their definition as friends.
I say "AFAIK" ADL finds it: that's the very next sentence after the bit I quoted :-)
Please, can you post an example with "matching declaration in namespace scope before the class definition"? Do you mean something like this? liveworkspace.org/code/1l2Wz3$0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.