2

我有一个类,它在类中声明和定义了一个友元函数,我从类中的另一个函数调用这个函数。Clang 编译器 (3.3) 抱怨友元函数的未声明标识符。我已经用 MSVC 和 gcc 编译了这段代码,它适用于两个编译器,但现在使用 Clang 端口我遇到了这个问题。这是问题的简化示例:

class foo
{
  friend void bar() {}
  void asd() {bar();}
};

在 Clang 中,我得到:error : use of undeclared identifier 'bar'。如果我在类外声明/定义 pla(),它可以正常工作,但是我有一些宏迫使我在类中定义函数。这是 Clang 中的一些已知问题,还是 Clang 在仍然符合 C++ 标准的同时对 C++ 名称查找更加迂腐?在类中定义/声明函数时是否有一些已知的解决方法?

4

2 回答 2

6

相关规则见 §7.3.1.2 [namespace.memdef]/p3:

在命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类或函数,则友元类或函数是最内层封闭命名空间的成员。在该命名空间范围内(在授予友谊的类定义之前或之后)提供匹配声明之前,未限定查找 (3.4.1) 或限定查找 (3.4.3) 无法找到朋友的名称。如果调用友元函数,则可以通过名称查找找到其名称,该名称查找考虑来自与函数参数类型相关联的命名空间和类的函数(3.4.2)。

换句话说,当一个friend函数只在类内内联定义而从未在类外声明时,唯一可以找到它的方法是通过 ADL,它不适用这里,因为bar()它不带参数。在非 ADL 名称查找之前,必须在最里面的封闭命名空间中找到该函数的匹配声明。

于 2014-07-06T21:21:42.867 回答
3

根据 C++ 标准

7 这样的函数是隐式内联的。在类中定义的友元函数在定义它的类的(词法)范围内。在类外定义的友元函数不是(3.4.1)。

我理解单词“词法范围”的方式是它的名称在类范围中可见。因此,考虑到这一点,Clang 中似乎存在一个错误。

虽然我没有找到术语“词汇范围”的定义。所以这一段可以解释为朋友功能本身可以访问类成员,而无需他们的资格或我上面所说的方式。

例如这样的代码编译没有问题

struct A
{
    friend void f() { x = 20; }
    static int x;
};

int A::x;

int main() {}

但是这个没有编译

struct A
{
    friend void f();
    static int x;
};

int A::x;

void f() { x = 20; }

int main() {}
于 2014-07-06T20:41:31.097 回答