朋友声明:这是clang中的bug吗

Friend declarations: Is this a bug in clang?

本文关键字:中的 bug clang 这是 声明 朋友      更新时间:2023-10-16

§3.4.1/3有以下示例:

typedef int f;
namespace N
{
    struct A
    {
        friend void f(A &);
        operator int();
        void g(A a)
        {
            int i = f(a);
        }
    };
}

由于编译器在声明int i = f(a);中的名称f的普通查找中没有看到友元声明N::A::f(A&),因此编译时没有出现错误(参见实际示例),根据§7.3.1.2/3,这是正确的。

§7.3.1.2/3(重点是我的):

首先在命名空间中声明的每个名称都是命名空间。如果非局部类中的友元声明首先声明类或函数友元类或函数是最里面的封闭命名空间。找不到朋友的名字不合格查找(3.4.1)或通过合格查找(3.4.3)直到在该命名空间范围中提供匹配声明(在授予友谊的类定义之前或之后)。

现在,如果我们包括声明

struct A;
void f(A&);

namespace N中的上述代码段中,struct A之前,代码将正确地发出错误(参见实际示例),因为现在函数::f(A&)是通过在表达式int i = f(a);中查找名称f来找到的,这符合§7.3.1.2/3。

但是,如果我们包括申报

void f(A&);

namespace N中,struct A之后,代码出人意料地没有发出任何错误,请参阅实际示例。

不,clang做的是正确的。这不是一个bug。

您误读了本规范摘录的上下文。这一段所传达的唯一内容涉及友元函数声明和它们的目标函数如何相互关联它与调用该特定函数的常规规则无关,在这方面也没有任何变化

因此,编译不会失败,因为函数f()的原型在您尝试使用它时尚未声明(相反,它会找到具有相同名称的typedef)。

如果您修改代码以在类之外实现A::g()成员,您会注意到,当f()原型出现在实现之前时编译失败,而当原型出现在它之后时编译成功——这正是如果没有友元声明时所期望的情况。

在您引用的同一段(§7.3.1.2/3)中,有一个示例澄清了查找规则:

// Assume f and g have not yet been defined.
void h(int);
template <class T> void f2(T);
namespace A {
    class X {
        friend void f(X); // A::f(X) is a friend
        class Y {
            friend void g(); // A::g is a friend
            friend void h(int); // A::h is a friend
            // ::h not considered
            friend void f2<>(int); // ::f2<>(int) is a friend
        };
    };
    // A::f, A::g and A::h are not visible here
    X x;
    void g() { f(x); } // definition of A::g
    void f(X) { /* ... */} // definition of A::f
    void h(int) { /* ... */ } // definition of A::h
    // A::f, A::g and A::h are visible here and known to be friends
}

因此编译器工作正常。