朋友功能在课堂上不可见

时间:2014-05-08 11:42:40

标签: c++

我有以下代码:

struct M {
    friend void f() {}
    M() {
        f(); // error: 'f' was not declared in this scope
    }
};

int main() {
    M m;
}

Live example

g ++ 4.8和clang3.4都无法编译,因为fM内不可见,或者他们说。

但是,标准提供了类似代码的示例

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,它是在使用它的同一个类中定义的。

两个编译器都不太可能有同样的错误 那么,我错过了什么?

4 个答案:

答案 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