与外部"C"函数的友谊似乎需要::限定名称

friendship with extern "C" function seems to require :: to qualify name

本文关键字:定名称 友谊 外部 函数      更新时间:2023-10-16

尝试用extern "C"函数使class为朋友,下面的代码工作:

#include <iostream>
extern "C" {
  void foo();
}
namespace {
  struct bar {
    // without :: this refuses to compile
    friend void ::foo();
    bar() : v(666) {}
  private:
    int v;
  } inst;
}
int main() {
  foo();
}
extern "C" {
  void foo() {
    std::cout << inst.v << std::endl;
  }
}

但是我很惊讶地发现,在g++ 4.6.1和4.4.4中,我必须在friend void ::foo();中明确地写::,否则友谊就不起作用了。这个::只有当它是extern "C"时才需要。

  1. 这是编译器错误/问题吗?我没有预料到这种行为。
  2. 如果它不是一个错误,为什么这是必需的,但只有当它是extern "C",而不是没有它?如果更改了名称查找规则,那么需要这样做吗?

我难住了。可能有一些我找不到的规则

[n3290: 7.3.1.2/3]:在命名空间中首先声明的每个名称都是该名称空间的成员。如果非局部类中的friend声明首先声明一个类或函数,友类或函数是a最内层封闭命名空间的成员。朋友的名字是非限定查找(3.4.1)或限定查找(3.4.3)未找到这意味着类或函数的名称是不合格的。直到其中提供了匹配声明命名空间作用域(在类定义授予之前或之后)友谊)。如果调用友元函数,则可以通过考虑来自名称空间和类的函数的名称查找与函数参数的类型相关联(3.4.2)。如果friend声明中的name既不是限定的,也不是模板id声明是一个函数或一个详细类型说明符查找以确定实体是否先前已声明不应考虑最内层封闭之外的任何作用域名称空间。 [. .]

最里面的封闭命名空间是匿名命名空间,并且您没有限定函数名,因此找不到该名称。

命名空间也不需要是匿名的。

请注意,问题中的extern "C"是一个转移注意力的词,因为下面的语句也因为同样的原因而失败:

void foo();
namespace {
struct T {
   friend void foo();
   private: void bar() { cout << "!"; }
} t;
}
void foo() { t.bar(); }
int main() {
   foo();
}
/*
In function 'void foo()':
Line 7: error: 'void<unnamed>::T::bar()' is private
compilation terminated due to -Wfatal-errors.
*/

[替代测试用例,改编自原始代码]