2

[namespace.memdef]/3(重点是我的):

如果非本地类中的友元声明首先声明了类、函数、类模板或函数模板106,则友元是最内层封闭命名空间的成员。友元声明本身不会使名称对非限定查找 (6.4.1) 或限定查找 (6.4.3) 可见。[ 注意:如果在命名空间范围内提供了匹配的声明(在授予友谊的类定义之前或之后),则朋友的名称将在其命名空间中可见。—end note ] 如果调用友元函数或函数模板,则可以通过名称查找找到其名称,该名称查找考虑来自与函数参数类型相关联的命名空间和类的函数(6.4.2)。如果友元声明中的名称既不是限定词也不是模板ID,并且声明是函数或详细类型说明符,则确定实体是否先前已声明的查找不应考虑最内层封闭命名空间之外的任何范围. [注意:其他形式的友元声明不能声明最内层封闭命名空间的新成员,因此遵循通常的查找规则。—尾注] [示例:...

无论朋友声明是否是其命名空间中的第一个声明,下面的代码都能正确执行。

#include<iostream>

namespace N{
    struct A;
    void f(A&);         // If you comment out this declaration, i.e., if the
                        // friend declaration turns out to be the first
                        // declaration in namespace N, the code will still
                        // execute correctly, i.e., printing the same result
                        // below.

    struct A {
        friend void f(A& ra) { std::cout << "friend void f(A&)\n" << ra.i; }
    private:
        int i = 100;
    };
}

N::A a;
int main(){
    f(a);
}

此代码段打印出以下内容:

friend void f(A&)
100
4

1 回答 1

2

它是在ADL中找到的,因为您从 namespace 传递了一个参数N。示例可以更改为:

namespace N{
    void f(int); // If you comment out this declaration, i.e., if the
                 // friend declaration turns out to be the first
                 // declaration in namespace N, the code will fail to compile.

    struct A {
        friend void f(int) { std::cout << "friend void f()\n"; }
        private:
        int i = 100;
    };
}

int main(){
    N::f(1);
}

在线编译器

于 2018-08-12T14:46:04.337 回答