2

§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);
        }
    };
}

编译时没有错误(参见live example ),因为编译器在声明中的名称的N::A::f(A&)普通查找中看不到友元声明,根据 §7.3.1.2/3 这是正确的。fint i = f(a);

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

在命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类或函数,则友元类或函数是最内层封闭命名空间的成员。在该命名空间范围内(在授予友谊的类定义之前或之后)提供匹配声明之前,未限定查找 (3.4.1) 或限定查找 (3.4.3) 无法找到朋友的名称。

现在,如果我们包含声明

struct A;
void f(A&);

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

但是,如果我们包含声明

void f(A&);

namespace N之后代码出人意料地struct A没有发出任何错误,请参见live example

4

2 回答 2

2

No, clang is doing the right thing. 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).

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.

于 2014-09-04T20:35:14.113 回答
1

在您引用 ( ) 的同一段中,§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
}

所以编译器可以正常工作。

于 2014-09-04T18:57:20.367 回答