简体   繁体   中英

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

Hidden friends need to be fully defined inline, ie, 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;
};

Hidden friends can be defined out of line, but then they are not hidden in that TU. As an example, consider this header:

class A {
    // this is hidden friend defined inline
    friend int operator+(A, int) { return 0; }
    // this is hidden friend defined out of line
    friend int operator+(int, A);
    // not a hidden friend (see below)
    friend int operator+(A, A);
};
int operator+(A, A); // this is no longer hidden friend in any TU

and then a separate cpp file:

#include "a.hpp"

// This is not a hidden friend in this TU, but is in other TUs.
int A::operator+(int, A) {
    return 2;
}

Doing this is useful when you have operators/ADL customization points that depend on other large headers for their implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM