为什么不能在本地class定义友元函数?

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

我有以下 C++ 代码片段。在 main() 函数中声明了一个 class。

为什么不能在本地定义友元函数class?

#include<iostream>

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

因为局部 class 的成员函数必须完全在 class 函数体内定义,友元函数不是成员函数。我们在 class 内声明友元函数并在 class.

外定义

根据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.

这是有实际原因的。首先,内联好友定义无法通过合格或非合格查找找到。它只能由 ADL 找到。因此,如果我们从您的示例中获取 class,将其放在全局范围内并尝试调用 Bar:

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

我们将收到通知,指出 Bar 未在该范围内声明。所以如果它在本地 class。你不能从成员那里调用它。你不能在函数内部调用它。你 可能 称呼它的唯一方式涉及一些篮球或 ADL。所以语言不允许这样做。它不被视为有用的功能。

这没有令人信服的技术原因。你说 ADL 找不到它?好吧,这基本上是问题的一部分:为什么 ADL 找不到它?只需扩展 ADL 即可找到它。

此限​​制的一个设计层面原因可能源于对友元声明中不合格名称的语言处理。

在本地 classes 的友元声明中使用的非限定名称是指来自 最近的非 class 范围 的名称。这种对不合格名称的处理非常重要,因为这是本地 classes 可以相互引用的唯一方式(因为显而易见的原因,本地 classes 没有 qualified 姓名)

int main()
{
  class B;

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

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

此规则也适用于具有非限定名称的 friend function 声明。 C++ 没有局部函数,但这样的友元声明仍然可以引用函数的局部非定义声明(这是完全合法的)

void foo() {}

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

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

现在,如果 在本地 class 中定义 友元函数(当然是使用不合格的名称),您认为应该发生什么情况?这样的声明引入了什么功能?具体分到什么范围?根据定义,它不是 class 的成员,因为友元声明不引入 class 成员。它不能是最近的封闭局部作用域的成员,因为那样会使它成为 局部函数,而 C++ 不支持局部函数。

我们不能只是统一地更改友元声明中所有非限定名称的行为,并说它们现在应该引用最近的封闭 namespace 作用域中的名称,因为那样会留下无法引用本地 classes(如上所示)。

解决这种情况的唯一方法是只使 in-class 友元函数定义 引用(并定义)最近的封闭 [=30] 中的函数=]命名空间范围。此类函数只能通过 [修改后的] ADL 调用(假设我们同意)。但这意味着我们必须对友元函数 definitions 中的非限定名称给予不同的处理(与非定义友元声明相反)。这将是相当不雅和混乱的。因此,语言作者决定反对它。

请注意,在 C++14 之后,这一点的重要性可能会显着增加,这让我们在函数中推导出 auto return 类型。在那之后,本地 classes 变得几乎不像以前那样 "local"

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 
}