问题
Let us define f
, as a friend function of S
, inside the declaration of S
:
struct S
{
friend void f() {}
};
I cannot find a way to call f
.
Is it true, then, that such an inline friend function can only be called with argument-dependant lookup?
struct S
{
friend void f() {}
friend void g(S const&) {}
} const s;
int main()
{
// f(); // error: 'f' was not declared in this scope
// S::f(); // error: 'f' is not a member of 'S'
g(s);
// S::g(s); // error: 'g' is not a member of 'S'
}
Bonus: what if I want to get a function-pointer/std::function
/lambda to g
?
回答1:
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
).
回答2:
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.
回答3:
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
来源:https://stackoverflow.com/questions/51304560/is-adl-the-only-way-to-call-a-friend-inline-function