After searching aroung SO, one question taught me that the lexical scope of an inline friend function is the class it's defined in, meaning it can access e.g. the typedef
s in the class without qualifying them. But then I wondered what is the actual scope of such a function? GCC at least rejects all my attempts to call it. Can a function such as in the example ever be called through means other than ADL, which is not possible here thanks to no arguments?
Standard quotations are appreciated, as I currently can't access my copy of it.
namespace foo{
struct bar{
friend void baz(){}
void call_friend();
};
}
int main(){
foo::baz(); // can't access through enclosing scope of the class
foo::bar::baz(); // can't access through class scope
}
namespace foo{
void bar::call_friend(){
baz(); // can't access through member function
}
}
results in these errors:
prog.cpp: In function ‘int main()’:
prog.cpp:9: error: ‘baz’ is not a member of ‘foo’
prog.cpp:10: error: ‘baz’ is not a member of ‘foo::bar’
prog.cpp: In member function ‘void foo::bar::call_friend()’:
prog.cpp:15: error: ‘baz’ was not declared in this scope
"The C++ Programming Language 3rd Edition (Stroustrap)" : p279:
I. "Like a member declaration, a friend declaration does not introduce a name into an enclosing scope"
II. "A friend class must be previously declared in an enclosing scope or defined in the nonclass scope immediately enclosing the class that is declaring it a friend"
III. "A friend function can be explicitly declared just like friend classes, or it can be found through its argument types (§8.2.6) as if it was declared in the nonclass scope immediately enclosing its class."
IV. "It follows that a friend function should either be explicitly declared in an enclosing scope or take an argument of its class. If not, the friend cannot be called. For example:"
But in your case there is more to it that has to do with the namespace, because if you put the proper declaration in foo e.g.:
does not compile. However, if you declare it outside foo is works like a charm. Now consider that in fact, global, local, struct, and classes are in fact namespaces. Now this leads to the conclusion that the
baz(const &)
is implicitly defined in the global scope.This compiles:
Therefore, there are two issues:
Thanks, hope it helps, but certainly, I liked the challenge :) .
Interesting!
It seems that the compiler does not know what scope it belongs to (and to be honest there are no clues) and thus puts in in no scope. Some standard digging coming up I suppose.
Note: If you explicitly add a declaration to a particular scope then it starts to work as expected.
Digging the standard I find:
11.3 Friends [class.friend]
Paragraph 6
Paragraph 7
Note:
A free standing function that does not take a parameter is not much use as a friend. As it will have no object on which to take advantage of its friendship (I suppose file scope static storage duration objects).
In this Example,
foo::baz()
is inaccessible because the namebaz
is not visible in scope of namespacefoo
. If I remember correctly (§ 3.4/2) applies here.foo::bar::baz()
is inaccessible because friends aren't members of class and the scope of inline friend function is namespace or class in which their definition exists therefore, you can't access them outside of that scope.If you put the declaration of
baz()
infoo
the name of functionbaz
will be visible infoo
and the definition will be looked up in the nested scope ofbar
.When you declare a
friend
function with an unqualified id in a class it names a function in the nearest enclosing namespace scope.If that function hasn't previously been declared then the
friend
declaration doesn't make that function visible in that scope for normal lookup. It does make the declared function visible to argument-dependent lookup.This is emphasised in many notes, but the definitive statement is in 7.3.1.2/3 (of ISO/IEC 14882:2011):
I think you are confusing
friend
andprivate
. By declaring function afriend
you are granting it access to your private members, and not grating other functions access to it. Anyway, any member function of astruct
is accessible by any object becausestruct
members are public by default.However, in your case
baz
isn't accessible because by doingfriend void baz(){}
you didn't really declare the functionbaz
, you just said that it is afriend
function. You can just remove thefriend
keyword, and it will solve all the issues.