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).