What is the reason to we can not define friend function in local class?

2.2k views Asked by At

I have a following snippet code of c++. Declared a class inside main() function.

What is the reason to we can not define friend function in local class?

#include<iostream>

int main()
{
    class Foo
    {
        void foo() {} // Ok
        friend void Bar(){}; // Error
    };
}
3

There are 3 answers

0
StoryTeller - Unslander Monica On BEST ANSWER

There's a practical reason. First and foremost, an inline friend definition cannot be found by either qualified or unqualified lookup. It can only by found by ADL. So if we take the class from your example, put it in global scope and try to call Bar:

class Foo
{
    friend void Bar(){};
    void foo() {
      Bar();
    }
};

We'll be notified that Bar was not declared in that scope. So if it was in a local class. You can't call it from the members. You can't call it inside the function. The only way you may call it involves either some hoops or ADL. So the language just doesn't allow for it. It's not deemed a useful feature.

1
msc On

Because member functions of a local class have to be defined entirely inside the class body and friend function not a member function. We declared friend functions inside class and defined outside of class.

According to cppreference:

Local classes

  • A local class cannot have static members
  • Member functions of a local class have no linkage
  • Member functions of a local class have to be defined entirely inside the class body
  • Local classes other than closure types (since C++14) cannot have member templates
  • Local classes cannot have friend templates
  • Local classes cannot define friend functions inside the class definition
  • A local class inside a function (including member function) can access the same names that the enclosing function can access.
0
AnT stands with Russia On

There is no convincing technical reason for this. ADL can't find it, you say? Well, that's basically part of the question: why can't ADL find it? Just extend ADL to make it find it.

One design-level reason for this limitation is probably rooted in the language treatment of unqualified names in friend declarations.

Unqualified names used in friend declarations in local classes refer to names from nearest enclosing non-class scope. This treatment of unqualified names is critically important, since this is the only way local classes can refer to each other (since for obvious reasons, local classes do not have qualified names)

int main()
{
  class B;

  class A {
    int x;
    friend B; // refers to local `B`
  };

  class B {
    void foo(A &a) { a.x = 42; }
  };
}

This rule is also applied to friend function declarations with unqualified names. C++ does not have local functions, but such friend declarations can still refer to a local non-defining declaration of a function (which is perfectly legal)

void foo() {}

int main()
{
  void foo(); // refers to `::foo`

  class A {
    friend void foo(); // refers to local `foo`, which is `::foo`
  };
}

Now, what would you propose should happen when one defines a friend function in a local class (using an unqualified name, of course)? What function is introduced by such a declaration? Into what scope, specifically? By definition, it is not a member of the class, since friend declarations do not introduce class members. It cannot be a member of the nearest enclosing local scope, since that would make it a local function and C++ does not support local functions.

We cannot just uniformly change the behavior of all unqualified names in friend declarations and say that they should now refer to names in the nearest enclosing namespace scope, since that would leave as with no way to refer to local classes (as shown above).

The only way out of this situation is to make only in-class friend function definitions refer to (and define) functions in the nearest enclosing namespace scope. Such functions would only be callable through [modified] ADL (and let's say we are OK with that). But that would mean that we'd have to give different treatment to unqualified names in friend function definitions (as opposed to non-defining friend declarations). This would be rather inelegant and confusing. So, the language authors decided against it.

Note that importance of this might have increased notably after C++14, which gave us deduced auto return types in functions. After that local classes became not even nearly as "local" as they used to be

auto foo() 
{
  struct S // Local class
  {
    void bar() {}
  };

  return S();
}

int main() 
{
  auto a = foo();
  a.bar(); // An object of local class used outside of its original scope

  typedef decltype(a) S; // Local type is "stolen" from its original scope
  S b;                   // and used to freely declare objects in a completely
  b.bar();               // different scope 
}