4

As described here C++11 style SFINAE and function visibility on template instantiation class member functions overshadow free functions. Using a fully qualified name usually works, however I am having a hard time with friend functions of other classes which are declared in-line. Consider the following example:

namespace N {

    struct C {
        friend int f(const C& c) {
            return 1;
        }
        friend int g(const C& c) {
            return 2;
        }
    };

    struct D {
        void f() {
            g(C{});            // ADL finds this
            ::N::f(C{});       // not found dispite full qualification
        }
    };
}

I think I understand what the problem is, as described here What's the scope of inline friend functions? inline friend function are usually found using ADL and not really visible in the enclosing namespace.

So my question is how should I change my code to make this work (aside from renaming one of the f's)?

Community
  • 1
  • 1
odinthenerd
  • 5,422
  • 1
  • 32
  • 61
  • Did you try forward declaring `class C` and prototyping the friend function at namespace-scope ([like this](http://ideone.com/XG8m5q))? Or did I misunderstand the question (I think I may have). – WhozCraig Jun 11 '14 at 16:52
  • I'm taking the unusual step of answering _and_ downvoting, because this should have been very clear to you from the answers on the question you linked to, and you could simply have requested clarification on those in comments if you needed a nudge. – Lightness Races in Orbit Jun 11 '14 at 17:18
  • @LightnessRacesinOrbit Down vote is fair enough, in retrospect it was quite an oversight to not forward declare ::N::C::f. Should I delete the question? – odinthenerd Jun 11 '14 at 17:35
  • @PorkyBrain: Nah it's okay – Lightness Races in Orbit Jun 11 '14 at 17:39
  • @LightnessRacesinOrbit I make it a point to solicit criticism, I wish other people would, the awesome content here on SO seems to be getting buried under a mountain of junk and I wanted to make sure this question was not considered part of that junk. – odinthenerd Jun 11 '14 at 17:44
  • @PorkyBrain: Yep, glad you take that approach – Lightness Races in Orbit Jun 11 '14 at 18:20

1 Answers1

5

It's because of the friendliness:

[C++11: 7.3.1.2/3]: If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by simple name lookup until a matching declaration is provided in that namespace scope [...]. If a friend function is called, its name may be found by the name lookup that considers function from namespaces and classes associated with the types of the function arguments (3.4.2) [i.e. ADL].

The fix is to simply provide that declaration:

namespace N {

    struct C {
        friend int f(const C& c) {
            return 1;
        }
        friend int g(const C& c) {
            return 2;
        }
    };

    int f(const C& c);
    int g(const C& c);

    struct D {
        void f() {
            g(C{});
            ::N::f(C{});
        }
    };
}

(live demo)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055