我有以下代码:
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
实例
g ++ 4.8和clang3.4都无法编译它,因为 f
内部不可见 M
,或者他们说。
但是,标准给出了类似代码的示例
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
并说
一个 friend
在类中定义的函数是在(词法)范围内
定义它的类。
(ISO / IEC 14882:2011 11.3朋友[class.friend] p6,p7)
从这个我无法理解编译器怎么找不到 f
它在使用它的同一个类中定义。
两个编译器都不太可能有相同的bug。
那么,我错过了什么?
友元声明声明了一个函数调用 f
在周围的命名空间是该类的朋友;但它没有引入这个名字 f
进入命名空间。除非在命名空间中声明,否则它不可用(除了依赖于参数的查找)。
相关规则是C ++ 11 7.3.1.2/3:
如果一个 friend
非本地类中的声明首先声明一个类或函数,友元类或函数是最内层封闭命名空间的成员。 找不到朋友的名字 通过非限定查找或限定查找,直到在该命名空间范围内提供匹配的声明。
这句引自C ++标准
类中定义的友元函数位于(词法)范围内
定义它的类。
意味着以下
9名称查找朋友函数定义中使用的名称
(11.3)在授予友谊的类别中内联定义应继续进行
如在成员函数定义中查找所述。
也就是说,从类范围开始搜索函数中使用的任何名称。
但是,在将在类外部声明函数之前,函数本身在命名空间中不可见。
所以在你的情况下,在类定义之前声明函数就足够了
void f() {}
struct M {
friend void f();
M() {
f();
}
};
int main() {
M m;
}
要么
void f();
struct M {
friend void f() {}
M() {
f();
}
};
int main() {
M m;
}
关键问题是在什么情况下编译器能够/允许找到您的函数声明。
对于将军 friend
函数,你必须在类之外声明它,以便编译器能够找到它。
但是有一个非常有用的例外:如果是 friend
function有一个类类型的参数,它能够找到没有附加声明的函数 参数依赖的名称查找。
这种情况实际上非常重要,因为通常你会想要一个 friend
用于访问类类型对象的函数。
请考虑以下示例:
#include <iostream>
struct M
{
friend void printI(int a) {
std::cout << a;
}
friend void print(const M& m) { // friend takes object of class type!
std::cout << "M";
}
void foo() {
printI(2); // ERROR - requires declaration!
print(*this); // OK!
}
};
int main()
{
M m;
m.foo();
printI(2); // ERROR - requires declaration!
print(m); // OK
}
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
上面的代码完美无缺。(在DevC ++上试过)
也尝试不在类中定义函数,因为它可能没有在它之外的范围,即在 main()
。
在试图打电话 f()
从 main()
你会收到一个错误,说明功能不存在。
因此,使用在类外定义函数 ::
运算符(如果需要),以便从任何地方访问函数都没有问题。
访问在类中定义的友元函数