0

最近关于 ADL 的一些关于 SO 的问题让我思考。基本上,我很困惑编译器在执行 ADL 时可以搜索哪些头文件?它是仅包含在用户代码中的那些,还是可以包含其他头文件,其中与用户代码中使用的名称空间相同?例如。std命名空间跨越多个头文件。但是,我可能只包括其中的一部分。现在,如果我定义一个不在此头文件子集中但在std名称空间中(在我未包含的文件中)的函数,它仍然是一个模棱两可的调用吗?我之所以有这个疑问,主要是因为关于这个问题的讨论

4

5 回答 5

4

以下是它的工作原理......将源代码编译为可执行文件有 3 个基本步骤:

  1. 预处理
  2. 汇编
  3. 链接

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

您在 Buzz 的评论中链接的代码的问题是您无法知道标准标头包含或不包含哪些标头。(好吧,你可以知道你是否去查看它们以找出答案,但标准并没有说明。)你的任何一个标题都可以并且显然确实包含<algorithm>. 一旦发生这种情况:

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

namespace std由于 ADL ,您的版本与中的定义之一变得模棱两可。

于 2011-02-04T17:35:30.933 回答
1

不会。只要您避免包含包含定义的标头(或包含包含另一个包含定义的标头的标头),就不会有模棱两可的调用。只要不包含 C++ 标准版本,您就可以定义自己的 iostream、字符串、向量等(尽管您可能已经包含了 std 命名空间的其他部分)。

于 2011-02-04T17:26:18.083 回答
1

ADL 纯粹是关于查找规则的。与所有名称查找一样,只能找到先前已声明的实体,因此如果头文件是发生特定声明的唯一位置,并且该头文件尚未直接或间接(尚未)包含,则由引入的名称无论有没有 ADL,该声明都将不可见。

(这并不完全正确,好像要查找的名称是模板定义中的依赖表达式,最终查找将在模板特化被实例化之前不会发生,在这种情况下,后续声明会影响查找的结果。 )

All(!) ADL 所做的是在尝试匹配函数调用表达式中的非限定 ID时扩展搜索的命名空间,以包含与函数调用表达式的参数“相关”的命名空间。

于 2011-02-04T17:35:50.570 回答
1

C++ 标准定义了每个包含文件将引入的名称,但它并没有说明只有这些名称才可用。

这意味着,从理论上讲,仅包括<vector>可能使std::map.

这是不幸的,因为

  1. 由于缺少包含文件而导致不正确的代码无论如何都可以编译,因为在特定实现中包含文件之间存在不可移植的依赖关系。

  2. 如果您的任何名称也是std. 这也可能表现为可移植性问题。

明确回答您的问题:ADL 将仅引用已看到的包含文件,但是您无法轻松知道它们是哪一个,因为在实现中允许标准文件包含另一个标准文件。

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

于 2011-02-04T17:59:07.163 回答
0

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

于 2011-02-04T17:28:52.430 回答