我有以下代码:
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 Friends [class.friend] p6, p7)
由此我无法理解编译器如何找不到
f
,它是在使用它的同一个类中定义的。
两个编译器不太可能有相同的错误。
那么,我错过了什么?
友元声明指出周围命名空间中名为
f
的函数是该类的友元;但它没有将名称 f
引入命名空间。在命名空间中声明它之前,它不可用(除了通过参数相关的查找)。
相关规则是C++11 7.3.1.2/3:
如果非本地类中的
声明首先声明了一个类或函数,则友元类或函数是最内层封闭命名空间的成员。 在该命名空间范围内提供匹配声明之前,通过非限定查找或限定查找都找不到好友的名称。friend
friend
函数,您必须在类之外声明它,以便编译器能够找到它。但是有一个非常有用的例外:如果
friend
函数具有类类型的参数,则由于依赖于参数的名称查找,它无需额外声明即可找到该函数。 这种情况实际上非常重要,因为通常您需要一个
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
}
类中定义的友元函数位于该类的(词法)范围内 定义它的类。的意思如下
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;
}