模板 ID 中的好友查找异常

Friend lookup exception from template-id?

本文关键字:查找 异常 好友 ID 模板      更新时间:2023-10-16

请考虑 [namespace.memdef]/3 中的以下子句:

如果friend声明中的名称既不是 限定也不是模板 ID 并且声明是一个函数或详细类型说明符,确定实体是否已事先声明的查找不应考虑最内层之外的任何范围 封闭命名空间。

模板 ID 和限定名称的异常是否有原因?就此而言,是否有理由将查找不是模板 ID 的非限定名称限制在最里面的封闭命名空间?此子句是否解决特定问题或用例?

为什么限制不适用于限定名称和模板 ID?

限定名称和模板 ID 不能将新成员引入封闭命名空间,这就是 [namespace.memdef]p3 中的注释试图说的:

[ 注意:其他形式的friend声明不能声明新的 最里面封闭命名空间的成员,因此遵循通常 查找规则。— 尾注 ]

因此,对于限定名称和模板 ID,不需要此类限制。

请注意,模板 ID 缺少模板参数的声明,限定 ID 可能会将名称引入遥远的、不相关的命名空间。


为什么会有限制?

这部分答案还不完整,但代表了"研究"的现状。请随时做出贡献。

由于N0783 - 命名空间问题和建议的决议"试图澄清当前未定义或未完全指定的许多命名空间问题",引入了该限制(可能?(。

1995年的这份文件载有关于通过友元声明引入的实体声明相关问题的两次启发性讨论。请记住,当时的名称查找规则是不同的:

  • 尚未引入依赖于参数的查找(*(
  • 根据当前规则,通过友元声明引入的名称无法通过纯非限定查找(无 ADL(找到,请参阅 [namespace.memdef]p3 和 CWG 1477。N0878 中的示例表明,当时可以通过纯非限定查找找到这些名称。

(*( 我能找到的最好的是 1996 年 3 月的 N0878,上面写着">最近对工作文件进行了更改,以添加"Koenig 查找规则">

首先,N0783 中的函数示例:

void f(char);
namespace A {
    class B {
        friend void f(char);   // ::f(char) is a friend
        friend void f(int);    // A::f(int) is a friend
        void bf();
    };
    void B::bf()
    {
        f(1);  // calls A::f(int);
        f('x');  // also calls A::f(int) because ::f is hidden
    }
}

第二个友元声明必须引入一个新函数。N0783 尝试指定在哪个范围内引入此声明。它建议

给定名称的所有友元声明必须在一个中声明实体 特定范围。

作为一般规则,以避免上述情况的意外。

所以问题是,他们在哪个范围内声明实体?有 两种可能性,要么

  1. 查找函数的先前声明时,请查找直到到达最近的封闭命名空间,或者
  2. 查找以前的声明时,请在所有封闭作用域中查找已声明的函数的名称。如果上一个 找到名称的使用,声明将注入该范围。 如果没有找到以前使用该名称,则朋友将被注入 最近的封闭命名空间范围。

规则 #2 意味着任何调用的函数的存在f 封闭范围(无论类型是否匹配(都足以 使友元声明注入该范围。

我认为规则#2显然是不可接受的。好友声明 在命名空间中将受到该命名空间的任何全局声明的影响 名字。考虑一下这对操作员功能意味着什么!这 在全球范围内存在任何operator+功能将强制 所有朋友operator+运营商也出现在全球范围内! 在全局范围内存在模板将具有相同的 影响。

对于类类型:

namespace N {
    class A { void f(); };
}
using namespace N;
namespace M {
    class B {
        friend class A;  // Without this rule
                         // makes N::A a friend
        B();
    };
    class A { void f(); };
}
void N::A::f() { M::B  b; }  // A friend under current rules
void M::A::f() { M::B  b; }  // A friend under proposed rules

根据现行规则,这两个示例都不那么有趣,因为通过好友声明引入的名称只能通过 ADL 找到。这种限制可能是历史文物。在引入ADL之后,需要更多的"研究"来跟踪这一限制的发展。