4

The friend function below is not found by ordinary lookup (§7.3.1.2/3), but is found by ADL (§3.4.2/4 second bullet point), so the code compiles and executes normally (live example). But the function f isn't declared in any namespace. For example, if you try replacing the call f(x); by any of these calls ::f(x);, A::f(x); or A::X::f(x);, the code will not compile. Which namespace does contain the declaration of this friend function? Does the Standard say anything about this?

#include <iostream>
namespace A {
    class X {
        int i;
        friend void f(X x) { std::cout << x.i << '\n'; }
    public:
        X():i(101){}
    };
}

int main()
{
    A::X x;
    f(x);
}
Wake up Brazil
  • 3,421
  • 12
  • 19
  • 1
    The Standard says lots about this. Briefly, the function `f` is a member of `A`, but its declaration is not. – aschepler Sep 05 '14 at 19:08
  • Using a qualified name suppresses argument-dependent lookup - which is the only lookup capable of finding a name declared in a friend declaration. This is why `f(x)` works but `A::f(x)` doesn't, even though `f` is a member of namespace `A`. – Igor Tandetnik Sep 05 '14 at 19:16
  • @IgorTandetnik Could you give a reference for this? Would that be §3.4.2/1? – Wake up Brazil Sep 05 '14 at 19:19
  • Yes, that would be **3.4.2/1** When the postfix-expression in a function call (5.2.2) is an **unqualified-id**, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched... Emphasis mine. – Igor Tandetnik Sep 05 '14 at 19:22
  • @IgorTandetnik Does the Standard say that `f` is a member of `namespace A` in this circunstance? – Wake up Brazil Sep 05 '14 at 19:24
  • **7.3.1.2/3** says that. You've asked this question before. – Igor Tandetnik Sep 05 '14 at 19:25
  • @IgorTandetnik I forgot about this. You're right. But I'll have to accept Vlad's answer, which I believe came before your comment. Thanks anyway! – Wake up Brazil Sep 05 '14 at 19:28

1 Answers1

5

From the C++ Standard

11.3 Friends

6 A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8), the function name is unqualified, and the function has namespace scope. [ Example:

class M { friend void f() { } // definition of global f, a friend of M,
                              // not the definition of a member function
};

—end example ]

Amd the other quote (7.3.1 Namespace definition)

3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template98 the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). —end note ] If a friend function or function template is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace. [ Note: The other forms of friend declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual lookup rules. —end note ]

I would like to mention that enclosing a function name in parentheses suppresses the argument-dependent lookup.

For this code

int main()
{
    A::X x;
    ( f )(x);
}

function f will not be found.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335