【问题标题】:Regarding friend function definition and namespace scopes关于友元函数定义和命名空间范围
【发布时间】:2017-09-06 11:15:04
【问题描述】:

我正在阅读此blog post section,并尝试使用提供的 sn-p。

namespace N {
// 2
class A {
friend void f(A) {} // 1
};
}

如果我理解正确,// 1 中的定义将在// 2 所在的位置注入名称f。 但是,它只能通过依赖于参数的查找获得。很好。

帖子里有一句话引起了我的注意:

7.3.1.2/3 命名空间成员定义 [namespace.memdef]p3

在命名空间中首先声明的每个名称都是该命名空间的成员。如果非本地类中的友元声明首先声明了一个类、函数、类模板或函数模板,则友元是最内层封闭命名空间的成员。友元声明本身不会使名称对非限定查找 (3.4.1) 或限定查找 (3.4.3) 可见。

请注意,没有任何地方声明由朋友声明引入的名称必须与声明和/或定义它的类的名称有任何特定关系,或者与该类有任何特定关系(就此而言)。

据此,我认为以下 sn-p 是有效的:

namespace N {
struct A {
};

struct B {
  friend void f(A) {
}
};

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

但它被 GCC7 和 Clang 4 拒绝。

t.cpp:19:3: 错误:'f' 未在此范围内声明

有趣的是,当我尝试使用 N::B 对象调用 f 时,出现以下错误:

t.cpp:12:6: 错误:无法将“b”从“N::B”转换为“N::A”

这是我的问题:

不应该通过 ADL 检测到 f(A) 吗?由于这两个类都在命名空间中,我不明白为什么会失败。我在标准中查看了关于朋友的部分,但没有找到相关部分。

我想知道f(A) 是在哪个范围内注入的,因为当我尝试通过调用f(B) 给出错误的参数类型时,GCC 能够找到它。

【问题讨论】:

    标签: c++ friend argument-dependent-lookup


    【解决方案1】:

    来自cppreference/cpp/language/friend

    在类或类模板X 内的友元声明中首次声明的名称成为X 的最内层封闭命名空间的成员,但不可用于查找(考虑X 的参数相关查找除外)除非在命名空间范围内提供了匹配的声明 - 有关详细信息,请参阅 namespaces


    来自cppreference/cpp/language/namespace

    由非本地类X 中的友元声明引入的名称成为X 最内层封闭命名空间的成员,但除非在命名空间范围,在类定义之前或之后。这样的名称可以通过 ADL 找到,它同时考虑命名空间和类。


    这与您的示例一致 - f 采用 A,这与封闭类的类型不同。

    如果您将示例更改为...

    namespace N {
    struct A {
    };
    
    struct B {
      friend void f(B) {
    }
    };
    
    int main() {
      N::B b;
      f(b);
    }
    

    ...它会编译。


    相关标准报价:

    $14.3 [class.friend]

    类的朋友是一个函数或类,它被授予使用该类的私有和受保护成员名称的权限。 [...]当且仅当该类是非本地类([class.local]),函数名称是非限定的并且该函数具有命名空间范围时,才能在类的朋友声明中定义函数。 [...] 这样的函数隐含地是一个内联函数。 在类中定义的友元函数在定义它的类的(词法)范围内。在类外定义的友元函数不是([basic.lookup.unqual])。

    【讨论】:

    • 这是有道理的,但我还有一件事不清楚。 struct Ainnermost enclosing namespace 不是命名空间N 吗?还是编译器会生成隐藏的命名空间?这可以解释为什么 ADL 在我的示例中不起作用。或者可能是因为 ADL 规则中的特殊情况?
    • @Dante:“但不能用于查找(除了考虑 X 的参数相关查找)” - 在这种情况下,XA。您正在尝试通过 B 使用 ADL。
    • 非常感谢,这让我想到了[basic.lookup.argdep]§4.2 和下面的一句话:Any namespace-scope friend functions or friend function templates declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup (11.3) 如果我理解正确的话,这个名字是在编译器之后注入到封闭的命名空间中的检查参数类型类中是否存在友元声明。这是有道理的。
    猜你喜欢
    • 1970-01-01
    • 2016-12-12
    • 2013-05-19
    • 2020-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 2012-06-11
    相关资源
    最近更新 更多