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?
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.
Related
Suppose we have a class foo from a namespace space which declares a friend function named bar, which is later on defined, like so:
namespace space {
struct foo {
friend void bar(foo);
};
}
namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
To my understanding, friend void bar(foo); declares bar to be a free function inside space taking a foo by value. To use it, we can simply do:
auto f = space::foo();
bar(f);
My understanding is that we don't have to say space::bar, because ADL will see that bar is defined in the same namespace as foo (its argument) and allow us to omit the full name qualification. Nonetheless, we are permitted to qualify it:
auto f = space::foo();
space::bar(f);
which works (and should work) exactly the same.
Things started to get weird when I introduced other files. Suppose that we move the class and the declaration to foo.hpp:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
}
#endif //PROJECT_FOO_HPP
and the definitions to foo.cpp:
#include "foo.hpp"
#include <iostream>
namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
notice that all I did was I moved (didn't change any code) stuff to a .hpp-.cpp pair.
What happened then? Well, assuming that we #include "foo.hpp", we still can do:
auto f = space::foo();
bar(f);
but, we are no longer able to do:
auto f = space::foo();
space::bar(f);
This fails saying that: error: 'bar' is not a member of 'space', which is, well, confusing. I am fairly certain that bar is a member of space, unless I misunderstood something heavily. What's also interesting is the fact that if we additionally declare (again!) bar, but outside of foo, it works. What I mean by that is if we change foo.hpp to this:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
void bar(foo); // the only change!
}
#endif //PROJECT_FOO_HPP
it now works.
Is there something with header / implementation files that alters the expected (at least for me) behaviour? Why is that? Is this a bug? I am using gcc version 10.2.0 (Rev9, Built by MSYS2 project).
There's a slight subtlety that the friend declaration, while it doesn't require a previous declaration of the function or class your class is befriending, does not make the function visible for lookup except via ADL.
cppreference:
A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.
This is why you're able to find bar(f) (performs ADL) but not space::bar(f) (fully qualifying the name means ADL is not invoked).
Calling code that doesn't find bar via ADL needs to see a declaration. In the version where everything is in one file, calling code will see the entire definition of space::foo. When you split it into an HPP and a CPP file, calling code only sees the friend declaration which provides limited accessibility.
As you identified, if you want to make the function visible via ordinary lookup, put a declaration of foo in "foo.hpp":
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
void bar(foo); // Now code that includes foo.hpp will see a declaration for bar
}
#endif //PROJECT_FOO_HPP
I have two source files, a.cpp and b.cpp. In a.cpp, I have a function, foo:
namespace ns { void foo() { std::cout << "foo!"; } }
In b.cpp, I have another function in namespace ns in which I'd like to prototype and call foo:
namespace ns
{
void bar()
{
void foo();
foo();
}
}
While the above is syntactically valid, it leads the compiler to think that foo is in the global namespace (or at least that's what I've deduced from the linker errors I get when I do this). My first two ideas to fix that were void ns::foo(); and namespace ns { void foo(); }, but neither is valid. Is it possible to correctly prototype this function inside bar?
Note that I know I could simply move this to the file scope or a header file, there have been many questions asked about this, but I want to specifically prototype it inside another function. My compiler is MSVC 14.0 with the latest update.
EDIT: Based on some tests I've done and our discussion in the comments, I believe this is an MSVC bug. Compare:
namespace ns
{
void bar()
{
void foo(); // link error, MSVC assumes global namespace
foo();
}
void foo() { }
} // namespace ns
This fails, as stated previously. However, moving the prototype out of the function makes MSVC correctly place the prototyped function in the enclosing namespace:
namespace ns
{
void foo(); // all fine
void bar()
{
foo();
}
void foo() { }
} // namespace ns
The standard is clear about this point:
3.3.2/11: (..) Function declarations at block scope and variable declarations with the extern specifier at block scope refer to
declarations that are members of an enclosing namespace (...)
Consequently:
void bar()
{
void foo(); // should refer to ns::foo() according to 3.3.2/11
foo();
}
and the linking should refer to the separately compiled function which has the same signature:
1.3.17 signature: <function> name, parameter type list , and enclosing namespace (if any) [Note: Signatures are used as a basis for
name mangling and linking.—end note ]
namespace A {
void F() {}
namespace B {
void F(int) {}
}
}
using A::B::F;
namespace A {
void G() {
F(); // OK
F(1); // Error: too many arguments to function void A::F()
}
}
int main() { return 0; }
I have this piece of code.
I defined two functions with same names but different signatures.
Then I use a using-declaration using A::B::F.
In A::G() compiler tries to resolve A::F() before A::B::F().
Are there any orders if there are such conflicts?
The deepest nested scope is searched first, and scopes are then searched outward if the name is not found. So first it would find a block-scope declaration of F inside G, if any; then it would find a declaration at the namespace scope of A, if any; and if that too failed it would search the global scope. Since using A::B::F; appears at global scope, A::F is always found first. Perhaps you should move the using declaration inside A.
It's definitely about placement.
namespace A {
void G() {
F(); // OK, A::F
using B::F;
F(1); // OK, A::B::F
}
}
This code does not compile:
class A;
void foo(A&) {
}
class A {
void foo() {
foo(*this); ///This does not compile
}
};
Errors:
error: no matching function for call to 'A::foo(A&)'
foo(*this);
^
note: candidate is:
note: void A::foo()
This can be solved by calling ::foo(*this);
However, let's consider the case we are in a namespace:
namespace bar {
class A;
void foo(A&) {
}
class A {
void foo() {
foo(*this); ///This does not compile
}
};
}
Is there any other way than calling explicitly bar::foo(*this);? I mean, is there any way to look up names in the next surrounding declarative region, i.e. the containing bar namespace?
The use case is similar to what seen here.
I mean, is there any way to look up names in the next surrounding declarative region,
i.e. the containing bar namespace?
No.
You can sort of do it the other way around:
void foo() {
using bar::foo;
foo(*this); /// OK now
}
Not within the method itself. However, you can do this in the .cpp file:
namespace bar {
namespace {
auto outerFoo = foo;
}
void A::foo() {
outerFoo(*this);
}
}
Note that the name outerFoo is a hidden implementation detail which cannot cause name collisions (since it's in an anonymous namespace).
I have been experimenting with code derived from the "C++ Seasoning" presentation by Sean Parent, and have boiled my problem down to the following code:
#include <memory>
struct container {
struct concept {
virtual ~concept() {}
virtual void foo_() = 0;
};
template <class T> struct model : concept {
model (T x) : data_(x) {}
void foo_() {
foo(data_); // Line 13
}
T data_;
};
template <class T>
container(T x) : self_(new model<T>(x)) {} // Line 20
std::unique_ptr<concept> self_;
friend void foo(container &c) { c.self_->foo_(); }
};
void foo(int i) // Line 27
{
}
int main()
{
int i = 5;
container c(i); // Line 34
foo(c);
}
The problem I have is that this code that compiles with g++, and yet not with Clang.
Clang gives me the following error messages:
prio.cpp:13:13: error: call to function 'foo' that is neither visible in the
template definition nor found by argument-dependent lookup
foo(data_);
^
prio.cpp:20:32: note: in instantiation of member function
'container::model<int>::foo_' requested here
container(T x) : self_(new model<T>(x)) {}
^
prio.cpp:34:15: note: in instantiation of function template specialization
'container::container<int>' requested here
container c(i);
^
prio.cpp:27:6: note: 'foo' should be declared prior to the call site
void foo(int i)
^
My understanding is that overload resolution during templates occurs at the point of instantiation. In this case, that is line 34 (as marked above.) At this point, the global "foo" function is known. And yet, it appears not to resolve.
Note for posterity: This was with Clang built from trunk on 14/Jan/14
Is this a bug in Clang then, or with g++?
Gcc is wrong in this case, the code should not compile; but this is completely unrelated to the template. Friend declarations are particular in that they provide a declaration for a namespace level entity, but the declaration is not visible for normal lookup until a namespace declaration is also seen by the compiler.
Consider the simplified example:
struct X {
friend void f(int); // [1]
void g() { f(1); } // [2]
};
void h() { f(1); } // [3]
void f(int); // [4]
void i() { f(1); } // [5]
The friend declaration [1] inside the X class provides a declaration for a namespace level function f taking an int, but that declaration is not visible at namespace level until a namespace level declaration is present in [4]. Both [2] and [3] will fail to compile, although [5] will compile since at that point the compiler will have parsed the function declaration.
So how can the declaration in [1] be used by the compiler to resolve a call? In this particular case never. The friend declaration can only be found by argument dependent lookup, but ADL will only look inside X if one of the arguments to the function call is of type X. In this case, the function does not have any argument X, so lookup will never use the friend declaration for anything other than lifting the restrictions of access to the variables of X.
That is:
struct Y {
friend void f(int) {}
};
Without a latter namespace level declaration for f will declare and define a function that cannot be used anywhere in your program (lookup won't ever find it).
The simple workaround for your problem is to provide a declaration for the function at namespace level before the definition of the class:
#include <memory>
void foo(int);
struct container { // ...