Access friend function defined in class
Asked Answered
O

2

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()?

Oraliaoralie answered 16/10, 2011 at 17:6 Comment(2)
+1: Well-formulated question.Castro
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!Censure
C
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).

Castro answered 16/10, 2011 at 17:19 Comment(0)
S
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).

Sempstress answered 16/10, 2011 at 17:13 Comment(6)
placing declaration in global namespace solves the problem, however placing it in main function generates linker error. thanks.Oraliaoralie
@scdmb: I am surprised about the linker error, it should be valid.Sempstress
No, placing the definition-declaration in main causes a compiler error. What Charles suggested is accurate. 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.Castro
@TomalakGeret'kal: I get the linker error too, can you help me on where I've misunderstood?Sempstress
@Charles: codepad.org Let's see! Did my working paste not accurately represent your suggestion of placing the declaration in main?Castro
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()Inexpedient

© 2022 - 2024 — McMap. All rights reserved.