简体   繁体   English

朋友声明:这是clang中的错误吗?

[英]Friend declarations: Is this a bug in clang?

§3.4.1/3 has the following example: §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);
        }
    };
}

Which compiles without errors (see live example ) as the compiler doesn't see the friend declaration N::A::f(A&) in the ordinary lookup for the name f in the declaration int i = f(a); 哪个编译没有错误(请参见实时示例 ),因为编译器在普通查找中未在名称int i = f(a);看到名称f的朋友声明N::A::f(A&) int i = f(a); and this is correct according to §7.3.1.2/3. 根据§7.3.1.2/ 3,这是正确的。

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

Every name first declared in a namespace is a member of that namespace. 首先在名称空间中声明的每个名称都是该名称空间的成员。 If a friend declaration in a nonlocal class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. 如果非本地类中的朋友声明首先声明了一个类或函数,则该朋友类或函数是最内层的封闭命名空间的成员。 The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope ( either before or after the class definition granting friendship ). 直到通过在名称空间范围中提供匹配的声明( 在授予友谊的类定义之前或之后 ),才可以通过非限定查找(3.4.1)或限定查找(3.4.3)找不到朋友的名称。

Now if we include the declarations 现在,如果我们包括声明

struct A;
void f(A&);

In the snippet above in namespace N , before the struct A , the code will correctly emit an error (see live example ), as now the function ::f(A&) is found by ordinary lookup for the name f in the expression int i = f(a); 在上面的namespace N的代码段中, struct A 之前 ,代码将正确发出错误(请参见实时示例 ),因为现在可以通过普通查找在表达式int i = f(a);找到名称f的函数::f(A&)了。 int i = f(a); and this is in accordance with §7.3.1.2/3. 并符合§7.3.1.2/ 3的规定。

However, if we include the declaration 但是,如果我们包含声明

void f(A&);

In namespace N , after the struct A , the code surprisingly doesn't emit any error, see live example . namespace N struct A ,该代码令人惊讶地不会发出任何错误,请参见实时示例

No, clang is doing the right thing. 不,c在做正确的事。 This is not a bug. 这不是错误。

You are misreading the context of this spec excerpt. 您误解了此规范摘录的上下文。 The only thing this paragraph is communicating relates to how friend function declarations and their target function get associated with each other. 本段唯一要传达的内容是关于朋友函数声明及其目标函数如何相互关联的。 It has nothing whatsoever to do with the usual rules around calling that particular function, and changes nothing in that regard. 它与调用该特定函数的通常规则无关,并且在这方面没有任何改变。

Compilation therefore does not fail because the prototype of the function f() has not yet been declared at the point you attempt to use it (and instead it finds the typedef with the same name). 因此编译不会失败,因为函数f()的原型尚未在您尝试使用它的位置声明(而是找到具有相同名称的typedef)。

If you alter your code to implement the A::g() member outside of the class, you will note that compilation fails when the f() prototype appears before the implementation and succeeds when the prototype appears after it -- exactly what you would expect to happen if the friend declaration was absent. 如果更改代码以在类之外实现A::g()成员,您会注意到,当f()原型出现在实现之前时,编译将失败,而当原型出现在实现之后时,则编译将成功-正是您想要的如果没有朋友声明,我希望会发生。

In the same paragraph you cited ( §7.3.1.2/3 ) there is an example clarifying the lookup rules: 在引用的同一段落(第§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
}

So the compiler works correctly. 因此,编译器可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM