Let us define f
, as a friend function of S
, inside the declaration of S
:
struct S
{
friend void f() {}
};
<
No. You should just declare function properly.
struct S;
inline void f();
inline void g(S const&);
struct S
{
friend void f() {}
friend void g(S const&) {}
} const s;
int main()
{
f(); // Ok
// S::f(); // error: 'f' is not a member of 'S'
g(s);
// S::g(s); // error: 'g' is not a member of 'S'
}
online compiler
The name f
is declared in a friend declaration, even it becomes the member of the namespace which contains S
, but it's not visible for name lookup, unless it's redeclared at namespace scope. If not, it could be found only by ADL.
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 ordinary name 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.
Is it true, then, that such an inline friend function can only be called with argument-dependant lookup?
Yes. As specified in [namespace.memdef]/3:
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 ([basic.lookup.unqual]) or qualified lookup ([basic.lookup.qual]).
Since the only declaration of f
is its inline definition, it's not made visible to qualified or unqualified lookup. ADL however, has a special provision for such friend functions, [basic.lookup.argdep]/4:
When considering an associated namespace, the lookup is the same as the lookup performed when the associated namespace is used as a qualifier ([namespace.qual]) except that:
- Any namespace-scope friend functions or friend function templates declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup ([class.friend]).
As for your bonus question, a lambda should do it:
auto exposed_g = [](S const& s){ g(s); };
It wraps the ADL into its body. Though the usual caveats about return type deduction apply. It will be a value (assuming you don't return void
).