我有一个类,它在类中声明并定义了友元函数,我从类中的另一个函数调用此函数。 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 ++标准?在定义/声明类中的函数时,是否有一些已知的解决方法?
答案 0 :(得分:5)
相关规则见§7.3.1.2[namespace.memdef] / p3:
首先在名称空间中声明的每个名称都是其中的一员 命名空间。如果非本地类中的朋友声明首先声明 朋友类或函数所属的类或函数 最里面的封闭命名空间。找不到朋友的名字 非限定查找(3.4.1)或通过限定查找(3.4.3)直到a 在该命名空间范围内提供匹配声明(或者 在授予友谊的类定义之前或之后)。如果是朋友 函数被调用,其名称可以通过名称查找找到 考虑来自名称空间和与之关联的类的函数 函数参数的类型(3.4.2)。
换句话说,当一个friend
函数只在一个类内部定义并且从不在它之外声明时,唯一的方法是通过ADL,这里不适用bar()
没有参数。在通过非ADL名称查找找到函数之前,必须在最里面的封闭命名空间中有一个匹配的函数声明。
答案 1 :(得分:1)
根据C ++标准
7这样的功能是隐式内联的。朋友函数定义在 class位于定义它的类的(词法)范围内。一个 在课外定义的友元函数不是(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() {}