Clang: a friend function defined within a class
Asked Answered
L

2

2

I have a class which has a friend function declared and defined inside the class and I'm calling this function from another function within the class. Clang compiler (3.3) complains for undeclared identifier for the friend function. I have compiled this code with MSVC and gcc and it works on both compilers but now with Clang port I'm getting this problem. Here's a simplified example case of the problem:

class foo
{
  friend void bar() {}
  void asd() {bar();}
};

In Clang I get: error : use of undeclared identifier 'bar'. If I declare/define pla() outside the class, it works fine, but I have some macros which force me to define the function within the class. Is this some known issue in Clang or is Clang somehow more pedantic about the C++ name lookup while still conforming the C++ standard? Is there some known workaround for it while defining/declaring the function within the class?

Langue answered 6/7, 2014 at 20:29 Comment(7)
Is bar() supposed to be a member of class foo? Is there any other declaration of bar()?Disputant
No, it's a free function which is defined within the class. No other declarations/definitions for bar()Langue
If the function is only declared and used within foo, why does it need to be friend? Just declare it static.Disputant
Also, I think you are making the class and its function and friend functions the opposite way. You would declare foo as a friend function if foo needs to call (or otherwise access) private member functions (or data) in the class. But for the member function asd to call foo, all you need is a prototype of foo before the class.Skinner
@GregHewgill It's also called outside of foo. I guess I simplified the example a bit too much, sorry. I think I can actually move the friend function definition outside to solve this problem and just define it as a friend function within the class definition.Langue
@JoachimPileborg I use friend to be able to define the free function within the class and the function also need to access private members of the class.Langue
Your minimized code doesn't compile in g++ either.Bateman
B
6

The relevant rule is found in §7.3.1.2 [namespace.memdef]/p3:

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 or function the friend class or function is a member of the innermost enclosing namespace. 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). If a friend function 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).

In other words, when a friend function is only defined inline inside a class and never declared outside it, the only way it can be found is through ADL, which does not apply here as bar() takes no arguments. There must be a matching declaration of the function in the innermost enclosing namespace before it can be found by non-ADL name lookup.

Bateman answered 6/7, 2014 at 21:21 Comment(1)
You wrote: In other words, when a friend function is only defined inline inside a class and never declared outside it, the only way it can be found is through ADL, .... This is blatantly wrong. Where in [namespace.memdef]/3 does it mention that the friend function is defined inside the class?Pisano
S
3

According to the C++ Standard

7 Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (3.4.1).

I understand words "lexical scope" such a way that its name is visible in the class scope. So taking this into account it seems that there is a bug in Clang.

Though I did not find the definition of the term "lexical scope". So this paragraph can be interpretated as that the friend function itself can access members of the class without their qualification or the way I said about above.

For example such code is compiled without problem

struct A
{
    friend void f() { x = 20; }
    static int x;
};

int A::x;

int main() {}

But this one is not compiled

struct A
{
    friend void f();
    static int x;
};

int A::x;

void f() { x = 20; }

int main() {}
Shew answered 6/7, 2014 at 20:41 Comment(3)
Interesting that you can access static members without qualification in a friend function defined in a class scope. Thanks for the explanation of "lexical scope".Langue
That statement points to §3.4.1, whose p9 says "Name lookup for a name used in the definition of a friend function (11.3) defined inline in the class granting friendship shall proceed as described for lookup in member function definitions. If the friend function is not defined in the class granting friendship, name lookup in the friend function definition shall proceed as described for lookup in namespace member function definitions." That seems to be what "lexical scope" is referring to, which also seems to match the other use of that term in §9.7/p4.Bateman
@Vlad This has nothing to do with the fact that the friend function is not defined inline. For example this code compiles without a problem.Pisano

© 2022 - 2024 — McMap. All rights reserved.