我有以下的c ++代码段。在main()
函数内声明了一个类。
我们无法在本地课程中定义好友函数的原因是什么?
#include<iostream>
int main()
{
class Foo
{
void foo() {} // Ok
friend void Bar(){}; // Error
};
}
答案 0 :(得分:3)
这是一个实际的原因。首先,通过限定或非限定查找无法找到内联好友定义。它只能由ADL发现。因此,如果我们从您的示例中获取该类,请将其置于全局范围内并尝试调用Bar
:
class Foo
{
friend void Bar(){};
void foo() {
Bar();
}
};
我们会收到通知,说明Bar
未在该范围内宣布。所以,如果是在当地的一个班级。你不能从会员那里打电话。你不能在函数内调用它。你可以调用它的唯一方法涉及一些箍或ADL。所以语言不允许这样做。它不被视为有用的功能。
答案 1 :(得分:1)
没有令人信服的技术原因。您说ADL找不到它吗?好吧,这基本上就是问题的一部分:为什么?ADL找不到它?只需扩展ADL以使其找到它即可。
此限制的一个设计级原因可能是由于对朋友声明中不合格名称的语言处理。
在本地类的朋友声明中使用的不合格名称是指最近的非类作用域中的名称。对待不合格名称至关重要,因为这是本地类可以相互引用的唯一方法(由于明显的原因,本地类没有合格名称)
int main()
{
class B;
class A {
int x;
friend B; // refers to local `B`
};
class B {
void foo(A &a) { a.x = 42; }
};
}
此规则也适用于名称不合格的朋友 function 声明。 C ++没有本地函数,但是这样的朋友声明仍然可以引用函数的本地非定义声明(完全合法)
void foo() {}
int main()
{
void foo(); // refers to `::foo`
class A {
friend void foo(); // refers to local `foo`, which is `::foo`
};
}
现在,当一个定义本地类中的一个朋友函数(当然,使用不合格的名称)时,您会怎么办?这样的声明引入了什么功能?具体到什么范围?根据定义,它不是该类的成员,因为friend声明不会引入类成员。它不能是最近的封闭本地范围的成员,因为这会使它成为 local函数,而C ++不支持本地函数。
我们不能仅仅在朋友声明中统一更改所有不合格名称的行为,并说它们现在应该引用最近的 namespace 范围内的名称,因为那样就无法引用本地类(如上所示)。
摆脱这种情况的唯一方法是仅使类内好友函数定义引用(并定义)最接近的 namespace 范围内的函数。此类函数只能通过[修改的] ADL调用(可以说我们可以接受)。但这意味着我们必须对好友函数 definitions 中的不合格名称进行不同的处理(与未定义的好友声明相对)。这将是相当不雅且令人困惑的。因此,语言作者对此表示反对。
请注意,在C ++ 14之后,此操作的重要性可能显着提高,这使我们推断出函数中的auto
返回类型。之后,本地类甚至不再像以前那样“本地化”
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
}
答案 2 :(得分:0)
因为本地类的成员函数必须完全在类体内定义,而友元函数不是成员函数。我们在类中声明了友元函数,并在类之外定义。
根据cppreference:
本地课程
- 本地班级不能拥有静态成员
- 本地班级的会员职能没有联系
- 必须在类主体
内完全定义本地类的成员函数- 闭包类型以外的本地类(自C ++ 14起)不能有成员模板
- 本地课程不能拥有朋友模板
- 本地类无法在类定义中定义友元函数
- 函数内的本地类(包括成员函数)可以访问封闭函数可以访问的相同名称。