模板标识的朋友查找异常? [英] Friend lookup exception from template-id?

查看:239
本文介绍了模板标识的朋友查找异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


如果 声明既不是
限定也不是 template-id ,声明是一个函数或 elaborated-type-specifier 以确定实体是否先前已被声明,不应考虑最内层
之外的任何范围包含命名空间。


原因为 template-id 与限定名称的例外?对于这一点,有没有理由查找一个非限定名称,不是一个 template-id 被限制在最内层的命名空间?

解决方案

为什么限制不适用于限定的名称, template-ids?



合格的名称和模板标识符无法将新成员引入封闭命名空间,这是[namespace.memdef] p3中的注释试图说:


[注意:其他形式的 friend 声明不能声明一个新的
成员的最内层的命名空间,因此遵循通常的
查找规则。 - 结束注释]


因此,对于限定名称和模板标识, / p>

请注意,template-id缺少模板参数的声明,qual-id可以将名字引入遥远的,无关的命名空间。






为什么会有限制?



不完全,但代表了研究的当前状态。随意捐款。



由于 N0783 - 命名空间问题和建议的解决方案尝试澄清目前未定义的一些命名空间问题或不完全指定。



本文从1995年开始,包含了两个启发性的讨论,涉及通过朋友声明介绍的实体声明。请记住,当时的名称查找规则是不同的:




  • 尚未引入依赖于参数的查找<

  • 根据当前规则,通过纯无条件查找(无ADL)找不到通过朋友声明引入的名称,请参见[namespace.memdef] p3和 CWG 1477 。来自N0878的示例表明这些名字可以通过当时的纯无限制查找找到。



(*)< sup>我能找到的最好的是 N0878 a>从1996年3月开始,其中



第一个工作文件最近更改了Koenig查询规则 ,函数的N0783示例:


  void f 

命名空间A {
class B {
friend void f(char); // :: f(char)是一个朋友
friend void f(int); // A :: f(int)是朋友

void bf();
};
void B :: bf()
{
f(1); // calls A :: f(int);
f('x'); //也调用A :: f(int)因为:: f是隐藏的
}
}


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


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


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


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


  1. 在查找函数的上一个声明时,一直查找到最近的封闭命名空间,或

  2. 查找上一个声明时,查找所有声明的函数的名称的所有包围范围。如果发现先前的
    使用该名称,则声明被注入该范围。
    如果没有找到以前使用的名称,朋友被注入到
    最近的包围命名空间范围。

规则#2意味着在
封闭范围中存在任何称为 f 的函数,无论类型是否匹配,都足以满足
引起朋友声明注入该范围。



我相信规则#2显然是不可接受的。命名空间中的朋友声明
将受到该
名称的任何全局声明的影响。考虑这对操作员功能意味着什么!
在全局范围中存在任何 运算符+ 函数将强制
all friend operator + 运算符出现在全局范围内!
在全局范围中存在的模板将具有相同的
效果。



 命名空间N {
class A {void f };
}

使用命名空间N;

命名空间M {
class B {
friend class A; //没有这个规则
//使N :: A成为朋友
B();
};
class A {void f(); };
}

void N :: A :: f(){M :: B b; } //当前规则下的一个朋友

void M :: A :: f(){M :: B b; } //建议规则下的朋友


有趣的在当前规则下,因为通过朋友声明引入的名称只能通过ADL找到。这可能是一个历史文物。 在推出ADL后,需要更多的研究来跟踪此限制的发展。


Consider the following clause in [namespace.memdef]/3:

If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.

Is there a reason for the exception for template-id along with the qualified name? For that matter, is there a reason for the lookup of an unqualified name that isn't a template-id to be restricted to the innermost enclosing namespace? Is there a specific problem or use-case that this clause solves?

解决方案

Why doesn't the restriction apply to qualified names and template-ids?

Qualified names and template-ids cannot introduce new members into the enclosing namespace, this is what the note in [namespace.memdef]p3 tries to say:

[ Note: The other forms of friend declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual lookup rules. — end note ]

Therefore, no such restriction is necessary for qualified names and template-ids.

Note that template-ids lack the declaration of the template-parameters, and qualified-ids could introduce names into distant, unrelated namespaces.


Why is there a restriction at all?

This part of the answer is still incomplete, but represents the current state of "research". Feel free to contribute.

The restriction has (probably?) been introduced due to N0783 - Namespace Issues and Proposed Resolutions which "attempts to clarify a number of namespace issues that are currently either undefined or incompletely specified".

This paper from 1995 contains two enlightening discussions of issues related to declarations of entities introduced via friend-declarations. Bear in mind that the name lookup rules back then were different:

  • Argument-dependent lookup had not yet been introduced(*)
  • Names introduced via friend-declarations are not found via pure unqualified lookup (no ADL) according to current rules, see [namespace.memdef]p3 and CWG 1477. The examples from N0878 suggest that those names could be found via pure unqualified lookup at that time.

(*) The best I could find was N0878 from March 1996, which says "A change was recently made to the working paper to add the "Koenig lookup rule""

First, the example from N0783 for functions:

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
    }
}

The second friend declaration must introduce a new function. N0783 tries to specify in which scope this declaration is introduced. It suggests

All friend declarations for a given name must declare entities in one particular scope.

as a general rule, to avoid the surprises of situations such as the above.

So the question is, which scope do they declare entities in? There are two possibilities, either

  1. When looking for a previous declaration of the function, look until the nearest enclosing namespace is reached, or
  2. When looking for a previous declaration, look in all enclosing scopes for the name of the function that was declared. If a previous use of the name is found, the declaration is injected into that scope. If no previous use of the name is found the friend is injected into the nearest enclosing namespace scope.

Rule #2 would mean that the presence of any function called f in an enclosing scope, whether or not the types match, would be enough to cause a friend declaration to inject into that scope.

I believe that rule #2 is clearly unacceptable. A friend declaration in a namespace would be affected by any global declaration of that name. Consider what this would mean for operator functions! The presence of any operator+ function in the global scope would force all friend operator+ operators to appear in the global scope too! The presence of a template in the global scope would have the same effect.

For class types:

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

Both examples are not as interesting under the current rules because names introduced via friend declarations are only found via ADL. It is possible this restriction is a historical artefact. More "research" is required to follow the development of this restriction after the introduction of ADL.

这篇关于模板标识的朋友查找异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆