C++中的参数依赖名称查找规则

问题描述:

最近在ADL上有一些问题让我想到了。基本上,我很困惑编译器在执行ADL时可以搜索哪些头文件?它只是用户代码包含的内容,还是可以包含其他头文件,其中包含用户代码中使用的相同名称空间?例如。命名空间跨越多个头文件。但是,我可能只包括它的一个子部分。现在,如果我定义的函数不在这个头文件子集中,但是在std命名空间中(在我没有包含的文件中),它是否仍然是一个模糊的调用?我得到了这个疑问,主要是因为在这方面的讨论questionC++中的参数依赖名称查找规则

+0

编译器如何神奇地猜测它看不到的模糊性? – 2011-02-04 17:46:25

+0

是的,看完现在的答案感觉有点傻。链接问题中的代码给了我一个错误。 – Naveen 2011-02-04 17:49:15

下面是它如何工作的?有3个源码编译成可执行的基本步骤:

  1. 预处理
  2. 编译

有零遮盖这些在C++中的步骤。包含指令是预处理指令,因此在编译之前发生。模板实例化是编译的一部分,因此它在预处理之后发生。编译器不会在当前翻译单元之外搜索任何内容。因此,不,ADL是一个编译时事件,不能搜索那些不包含的标题。

您的代码在评论中链接到Buzz的问题是,您无法知道标准头文件包含了哪些头文件。 (好吧,你可以知道你是否在寻找它,但标准没有说。)你的头文件中的任何一个都可以,并且显然包括<algorithm>。一旦出现这种情况:

http://www2.roguewave.com/support/docs/leif/sourcepro/html/stdlibref/merge.html

你的版本变得模糊,因为与ADL在namespace std的定义之一。

没有。只要避免包含包含该定义的头文件(或包括包含另一个包含定义的头文件的头文件),就不会有含糊不清的呼叫。只要没有包含C++标准版本(尽管您可能已经包含std名称空间的其他部分),您可以定义自己的iostream,字符串,向量等。

编译器通常工作的单个翻译单元上 - 这是在输入的所有源代码后预处理器在它发了一通。那时所有的头文件都已经递归地扩展了。问题是,当你包含一个给定的库头文件时,你不能假定它包含了什么其他文件等等。你可以随时检查,但我确定它是一个“实现细节”。

ADL纯粹是关于查找规则。与所有名称查找一样,只有先前已声明的实体可以被找到,所以如果头文件是唯一发生特定声明并且该头文件尚未被直接或间接包含的地方(然而),那么由该声明在使用或不使用ADL时都不可见。 (这并不完全正确,好像被查找的名称是模板定义中的依赖表达式,直到实例化模板专门化后才会发生最终查找,在这种情况下,后续声明会影响结果)

全部(!)ADL所做的是在函数调用表达式中尝试匹配未限定标识以扩展名称空间,以将函数调用表达式的参数包含到名称空间“相关”中。

C++标准定义了每个包含文件的名称将带入哪个名称,但它不会告诉只有那些将是可用的名称。

这意味着,理论上只包括<vector>可能会提供std::map

这是不幸的,因为这是不正确,因为丢失包含文件反正可以编译,因为之间不可移植的依赖关系的

  1. 代码包含在具体实施文件。

  2. 如果您的任何名称都是std中的名称,则可能会因为ADL而导致查找问题。这也可以表现为可移植性问题。

要明确地回答你的问题:ADL将仅指已经看到了包括文件,但是你不能可移植性知道他们是哪一个,因为实现一个标准的文件被允许包括其他标准文件。

所以ADL 可能看看所有可能的标准标题,但你不能指望。