I was reading this blog post section, and I tried to play around with the snippet that was provided.
namespace N {
// 2
class A {
friend void f(A) {} // 1
};
}
If I understood correctly, the definition in // 1
will inject the name f
where // 2
is located.
However it will only be available via argument-dependent lookup. Fine.
There is a sentence in the post that caught my attention:
7.3.1.2/3 Namespace member definitions [namespace.memdef]p3
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3).
Notice that nowhere is it stated that the name introduced by a friend-declaration must have any particular relation to name of the class it is declared and/or defined in, or any particular relation to the class at all (for that matter).
From this, I thought the following snippet would have been valid:
namespace N {
struct A {
};
struct B {
friend void f(A) {
}
};
int main() {
N::A a;
f(a);
}
But it's rejected by both GCC7 and Clang 4.
t.cpp:19:3: error: ‘f’ was not declared in this scope
The funny thing is that, when I try to call f
with a N::B
object, I get the following error:
t.cpp:12:6: error: could not convert ‘b’ from ‘N::B’ to ‘N::A’
So here's my question:
Shouldn't f(A)
be detected via ADL? Since both classes are in the namespace I don't see why this fails. I looked in the standard the section about friends, but failed to find a relevant section.
I wonder in which scope f(A)
was injected, since GCC is able to find it when I try to give the wrong argument type via calling f(B)
.
If the friend function is a member of another class, you need to use the scope resolution operator ( :: ). For example: class A { public: int f() { } }; class B { friend int A::f(); }; Friends of a base class are not inherited by any classes derived from that base class.
A scope is the portion of a program from where a namespace can be accessed directly without any prefix. At any given moment, there are at least three nested scopes.
In object-oriented programming, a friend function, that is a "friend" of a given class, is a function that is given the same access as methods to private and protected data. A friend function is declared by the class that is granting access, so friend functions are part of the class interface, like methods.
A friend function is a function that isn't a member of a class but has access to the class's private and protected members. Friend functions aren't considered class members; they're normal external functions that are given special access privileges.
From cppreference/cpp/language/friend
:
A name first declared in a friend declaration within class or class template
X
becomes a member of the innermost enclosing namespace ofX
, but is not accessible for lookup (except argument-dependent lookup that considersX
) unless a matching declaration at the namespace scope is provided - see namespaces for details.
From cppreference/cpp/language/namespace
:
Names introduced by friend declarations within a non-local class
X
become members of the innermost enclosing namespace ofX
, but they do not become visible to lookup (neither unqualified nor qualified) unless a matching declaration is provided at namespace scope, either before or after the class definition. Such name may be found through ADL which considers both namespaces and classes.
This is consistent with your example - f
takes an A
, which is not the same type as the enclosing class.
If you change your example to...
namespace N {
struct A {
};
struct B {
friend void f(B) {
}
};
int main() {
N::B b;
f(b);
}
...it will compile.
Related standard quote:
$14.3 [class.friend]
A friend of a class is a function or class that is given permission to use the private and protected member names from the class. [...] A function can be defined in a friend declaration of a class if and only if the class is a non-local class ([class.local]), the function name is unqualified, and the function has namespace scope. [...] Such a function is implicitly an inline function. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not ([basic.lookup.unqual]).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With