Interesting. Can't say as I've ever seen a friend function actually
*defined* inside a class. Is it portable?
[I thought I'd already answered this, but I don't see my
posting...]
It's a fairly well known idiom, first published, I think, by
Barton and Nackman. The committee took it into consideration
when changing the rules for name lookup; even then, breaking it
was considered to be something that would break too much code.
(It looks like this may be
related to a recent discussion about "injecting" a function into a namespace
via a friend declaration.)
Yup. Historically, it worked because friend names were injected
into the surrounding namespace scope (or file scope, given that
namespaces didn't exist). This injection caused problems
elsewhere (I forget what), and the committee did away with it.
But only because ADL could now be used to find the name.
Note that there are special cases which were broken. Consider
the following:
class A {} ;
class B
{
public:
B( A const& ) {}
friend void print( B const& ) {}
} ;
int main()
{
A anA ;
print( anA ) ;
return 0 ;
}
According to the old (pre-1998) rules, this is legal; print is
injected into the global namespace, name lookup in main finds
it, and overload resolution uses the convertion constructor to
convert the argument and call it. Under the new rules, there is
nothing in the arguments which relates to B, so the compiler
does not look there in ADL, and so the code fails to compile.
Many compilers (VC++ 8, Sun CC 5.8, g++ pre-4.0) still implement
friend injection; of the compilers I have access to, the only
one which complains about this code is g++ 4.1.0.
How is it affected by the visibility within that
class?
I think you mean access control. Visibility is a rather vague
term, related to name look up, and everything in a class
definition has the same "visibility". Access control (public,
private, etc.) only affects members, and a friend is not a
member.
Would it have to be in the a public section to be seen from outside,
even though it's not a member?
No.
Think about it for a minute. I can also declare the friend
outside of the class. Should it be accessible then, but not if
I don't.
A friend is not a member. Given something like:
namespace A {
class B {
friend void f() ;
} ;
}
The function declared by the friend declaration is A::f(), not
A::B::f(). Regardless of where it is defined. "Visibility"
(i.e. whether name lookup will find the symbol or not),
membership and access control or largely orthogonal issues. In
the example immediately above, f() is a member of A, and it's
fully qualified name is A::f(). It is, however, only visible in
contexts where name lookup looks into B: in member functions of
B, or when ADL kicks in for B. (Theoretically, it's also
visible in contexts like "someB.f()", after the dot. But in
those contexts, only members are considered, and since it's not
a member...)
Access control only affects members, and it is only applied
after name lookup and overload resolution have taken place; if
overload resolution chooses a private function, it's an error,
even if there is a public function of the same name which could
be called.
Can it be specified via
Foo:
rint(whatever), or is it just a member of the enclosing namespace?
It's just a member of the enclosing namespace. Even though it
isn't visible there
.