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

Fle*_*exo 13 c++ friend extern

尝试classextern "C"函数结交朋友,此代码有效:

#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;
  }
}
Run Code Online (Sandbox Code Playgroud)

但是我很惊讶地发现,使用g ++ 4.6.1和4.4.4我必须明确写入::,friend void ::foo();否则友谊不起作用.这::只是在需要的时候才需要extern "C".

  1. 这是编译器错误/问题吗?我没想到那种行为.
  2. 如果它不是一个bug,为什么这是必需的,但只有当它是,extern "C"而不是没有它?名称查找规则的变化如何使其成为必要?

我很难过.可能有一些我无法找到的规则.

Lig*_*ica 12

[n3290: 7.3.1.2/3]:首先在名称空间中声明的每个名称都是该名称空间的成员.如果friend非本地类中的声明首先声明一个类或函数,那么友元类或函数是最内层封闭命名空间的成员.通过非限定查找(3.4.1)或限定查找(3.4.3)95找不到朋友的名称这表示类或函数的名称是不合格的.直到在该命名空间范围内提供匹配的声明(在授予友谊的类定义之前或之后).如果调用了友元函数,则可以通过名称查找找到其名称,该名称查找考虑名称空间中的函数和与函数参数类型相关联的类(3.4.2).如果friend声明中的名称既不是限定名也不是模板标识 ,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑最内层封闭命名空间之外的任何范围.[..]

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

命名空间也不必是匿名的.

请注意,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.
*/
Run Code Online (Sandbox Code Playgroud)

[替代测试用例,根据您的原始代码改编]