我有以下代码:
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
,它是在使用它的同一个类中定义的。
两个编译器都不太可能有同样的错误 那么,我错过了什么?
答案 0 :(得分:12)
友元声明声明周围命名空间中名为f
的函数是该类的朋友;但它没有在名称空间中引入名称f
。除非在命名空间中声明它,否则它不可用(除了依赖于参数的查找)。
相关规则是C ++ 11 7.3.1.2/3:
如果非本地类中的
friend
声明首先声明一个类或函数,那么友元类或函数是最内层封闭命名空间的成员。 通过非限定查找或限定查找找不到好友的姓名,直到在该命名空间范围内提供匹配的声明为止。
答案 1 :(得分:3)
来自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;
}
答案 2 :(得分:2)
关键问题是在什么情况下编译器能够/允许查找函数声明。
对于通用friend
函数,您必须在类之外声明它,以便编译器能够找到它。
但是有一个非常有用的例外:如果friend
函数具有类类型的参数,则由于argument-dependent name lookup,它能够找到没有附加声明的函数。
这种情况实际上非常重要,因为通常你需要一个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
}
答案 3 :(得分:-4)
struct M {
friend void f() {}
M() {
f(); // error: 'f' was not declared in this scope
}
};
int main() {
M m;
}
上面的代码完美无缺。(在DevC ++上试过)
另外,尽量不要在类中定义函数,因为它可能没有在它之外的范围,即在main()
中。
在尝试从f()
致电main()
时,您会收到错误消息,指出功能不存在。
因此,使用::
运算符(如果需要)在类外定义函数,以便从任何地方访问函数都没有问题。
Access friend function defined in class