Search code examples
c++friendargument-dependent-lookup

Hidden friends: declarations and definitions


In his recent blog post Anthony Williams talks about hidden friends. The main idea, if I understood it correctly, is that functions declared as friends cannot be found by ADL in certain situations. Simple example:

namespace N {
    struct A {
        friend void foo(A) { }
    };

    struct B {
        operator A();
    };

    // (*)
    void bar(A) { }
}

void func() {
    N::A a;
    bar(a);   // OK, bar is found via ADL
    foo(a);   // OK, foo is found via ADL

    N::B b;
    bar(b);   // OK, bar is found via ADL
    foo(b);   // NOT OK, foo cannot be found
}

In all examples in the blog post, the friend functions are defined inside classes. Is it possible to declare a friend function and then define it later at the point (*), so that it remains hidden? It looks like hidden friends can only be defined in the class scope (or in another compilation unit).


Solution

  • Hidden friends need to be fully defined inline, i.e., inside of the definition of class. Yes, if you define friends somewhere else, where definition can cause namespace visibility, it would break restrictions based on hidden friends to be found as match by ADL search only, and as such be candidate for overload resolution.

    Further more in WG21 recommendations for specifying hidden friends, is noted that hidden friends are fully defined inline, like in this snippet:

    #include <ostream>
    #include <compare>
    class C  {
        friend ostream& operator << ( ostream&, C const& )  {}
        friend auto   operator <=>( C const&, C const& )  = default;
    };