Is ADL the only way to call a friend inline function?

江枫思渺然 提交于 2019-11-28 22:56:22

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).

songyuanyao

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 of X, 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.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!