来自template-id的朋友查找异常?

时间:2015-06-23 14:28:20

标签: c++ c++11 friend

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

  

如果friend声明中的名称都不是   限定也不是 template-id ,声明是函数或详细类型说明符,用于确定实体是否先前已声明的查找不应考虑任何范围在最里面   封闭命名空间。

是否有理由将 template-id 与限定名称一起使用?就此而言,是否有理由查找非限定名称,而 template-id 是否仅限于最内层的封闭名称空间?是否存在本条款解决的特定问题或用例?

1 个答案:

答案 0 :(得分:5)

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

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

  

[注意:其他形式的friend声明无法声明新的   最内层封闭命名空间的成员,因此遵循通常的   查找规则。 - 结束记录]

因此,限定名称和模板ID不需要这样的限制。

请注意,template-id缺少模板参数的声明,而qualified-id可能会将名称引入远程无关的命名空间。

为什么会有限制?

这部分答案仍然不完整,但代表了“研究”的现状。随意贡献。

由于N0783 - Namespace Issues and Proposed Resolutions“试图澄清当前未定义或未完全指定的一些命名空间问题”,因此引入了限制(可能是?)。

1995年的这篇论文包含两个有关通过朋友声明引入的实体声明相关问题的启发性讨论。请记住,当时的名称查找规则是不同的:

  • 尚未引入依赖于参数的查找(*)
  • 根据当前规则,通过纯粹的非限定查找(无ADL)找不到通过friend-declarations引入的名称,请参阅[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.   
  3. 查找以前的声明时,请查看声明的函数的名称的所有封闭范围。如果是以前的   找到名称的使用后,将声明注入该范围。   如果没有找到以前使用的名称,则注入该朋友   最近的封闭命名空间范围。
  4.         

    规则#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后,需要更多“研究”来遵循此限制的发展。