问题 朋友功能在课堂上不可见


我有以下代码:

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。
那么,我错过了什么?


10777
2018-05-08 11:42


起源

你在哪里宣布它? - Abhishek Bansal


答案:


友元声明声明了一个函数调用 f 在周围的命名空间是该类的朋友;但它没有引入这个名字 f 进入命名空间。除非在命名空间中声明,否则它不可用(除了依赖于参数的查找)。

相关规则是C ++ 11 7.3.1.2/3:

如果一个 friend 非本地类中的声明首先声明一个类或函数,友元类或函数是最内层封闭命名空间的成员。 找不到朋友的名字 通过非限定查找或限定查找,直到在该命名空间范围内提供匹配的声明。


12
2018-05-08 12:01





这句引自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;
}

3
2018-05-08 11:59



@Kate Gregory谢谢。由于操作“复制和粘贴”,这是一个错字。 - Vlad from Moscow
@Jonathan Mee谁允许你编辑我的帖子?!不要再这样做了! - Vlad from Moscow
AAAND那是我的坏事。谢谢你抓住它。 - Jonathan Mee


关键问题是在什么情况下编译器能够/允许找到您的函数声明。 对于将军 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
}

2
2018-05-08 12:01





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

int main() {
    M m;
}

上面的代码完美无缺。(在DevC ++上试过) 也尝试不在类中定义函数,因为它可能没有在它之外的范围,即在 main()。 在试图打电话 f() 从 main() 你会收到一个错误,说明功能不存在。 因此,使用在类外定义函数 ::运算符(如果需要),以便从任何地方访问函数都没有问题。 访问在类中定义的友元函数


-4
2018-05-08 11:59



它可能在一些古老的,不兼容的编译器上“完美”工作,但问题清楚地表明它不适用于至少两个现代编译器。 - Mike Seymour