42

There is such code:

#include <iostream>

class A{

public:
    friend void fun(A a){std::cout << "Im here" << std::endl;}
    friend void fun2(){ std::cout << "Im here2" << std::endl; }
    friend void fun3();
};

void fun3(){
    std::cout << "Im here3" << std::endl;
}

int main() 
{  
    fun(A()); // works ok
    //fun2(); error: 'fun2' was not declared in this scope
    //A::fun2(); error: 'fun2' is not a member of 'A'
    fun3(); // works ok
} 

How to access function fun2()?

scdmb
  • 15,091
  • 21
  • 85
  • 128
  • 7
    +1: Well-formulated question. – Lightness Races in Orbit Oct 16 '11 at 17:26
  • We see this kind of code in boost's smart pointer: intrusive_ptr, which made me first puzzle what that should be. For me it does not make sense to define it that way, rather define a friend somewhere in scope and mark a prototyp as friend in the class scope declaration, which is more readable! – Gabriel Jun 14 '14 at 14:59

2 Answers2

37
class A{

public:
    friend void fun(A a){std::cout << "Im here" << std::endl;}
    friend void fun2(){ std::cout << "Im here2" << std::endl; }
    friend void fun3();
};

Although your definition of fun2 does define a "global" function rather than a member, and makes it a friend of A at the same time, you are still missing a declaration of the same function in the global scope itself.

That means that no code in that scope has any idea that fun2 exists.

The same problem occurs for fun, except that Argument-Dependent Lookup can take over and find the function, because there is an argument of type A.

I recommend instead defining your functions in the usual manner:

class A {
   friend void fun(A a);
   friend void fun2();
   friend void fun3();
};

void fun(A a) { std::cout << "I'm here"  << std::endl; }
void fun2()   { std::cout << "I'm here2" << std::endl; }
void fun3();

Notice now that everything works (except fun3 because I never defined it).

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

The reason that you can call fun is that the friend declaration inside class A makes it visible via argument dependent lookup only. Otherwise friend declarations don't make the functions that they declare automatically visible outside of the class scope where the appear.

You need to add a declaration at namespace scope or inside main to make fun2 visible in main.

E.g.

void fun2();

fun3 is visible inside main because its definition (outside of the class) is also a declaration that makes it visible from main.

ISO/IEC 14882:2011 7.3.1.2:

The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship).

3.4.2 (Argument-dependent name lookup) / 4:

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

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • placing declaration in global namespace solves the problem, however placing it in main function generates linker error. thanks. – scdmb Oct 16 '11 at 17:18
  • @scdmb: I am surprised about the linker error, it should be valid. – CB Bailey Oct 16 '11 at 17:21
  • No, placing the _definition-declaration_ in `main` [causes a _compiler_ error](http://codepad.org/KrhX3kHL). [What Charles suggested is accurate](http://codepad.org/ERZrmowu). And next time please provide a testcase everytime you come back with an error report like that. See your C++ book for the difference between a declaration and a definition. – Lightness Races in Orbit Oct 16 '11 at 17:21
  • @TomalakGeret'kal: I get the linker error too, can you help me on where I've misunderstood? – CB Bailey Oct 16 '11 at 17:24
  • @Charles: http://codepad.org Let's see! Did my working paste not accurately represent your suggestion of placing the declaration in `main`? – Lightness Races in Orbit Oct 16 '11 at 17:25
  • I get linker error too. Strangely it works on codepad but fails to run on my laptop. I'm using ubuntu with gcc 4.5.2. I get the error `undefined reference to fun2()` – user803563 Jan 04 '12 at 22:01