最近有关于ADL的一些问题引起了我的注意。基本上,我很困惑哪些头文件编译器在执行ADL时可以搜索?它只是用户代码中包含的那些,还是包含其他头文件,其中用户代码中使用的是相同的命名空间?例如。 std
命名空间跨越多个头文件。但是,我可能只包括它的一个子部分。现在,如果我定义一个不在头文件子集中但是在std
命名空间中的函数(在我没有包含的文件中),它是否仍然是一个模糊的调用?我之所以怀疑这主要是因为对question
答案 0 :(得分:4)
以下是它的工作原理......将源代码编译为可执行文件有3个基本步骤:
C ++中的这些步骤没有重叠。 Include指令是预处理程序指令,因此在编译之前发生。模板实例化是编译的一部分,因此它在预处理之后发生。编译器不会在当前翻译单元之外搜索任何内容。因此,编译时事件ADL无法搜索未包含的标题。
您在Buzz评论中链接的代码问题在于您无法知道标准标题包含或不包含哪些标题。 (好吧,你可以知道你是否去查找它们,但是标准没有说明。)你的任何一个标题都可以包括<algorithm>
。一旦发生这种情况:
http://www2.roguewave.com/support/docs/leif/sourcepro/html/stdlibref/merge.html
由于ADL,您的版本与namespace std
中的一个定义不一致。
答案 1 :(得分:1)
没有。只要您避免包含包含定义的标头(或包含包含另一个包含定义的标头的标头),就不会有不明确的调用。您可以定义自己的iostream,字符串,向量等,只要没有包含C ++标准版本(尽管您可能已经包含了std命名空间的其他部分)。
答案 2 :(得分:1)
ADL纯粹是关于查找规则。与所有名称查找一样,只有先前声明的实体才能找到,所以如果头文件是发生某个声明的唯一地方,并且头文件没有被直接或间接地包含(尚未),那么由使用或不使用ADL时,该声明将不可见。
(这不完全正确,好像被查找的名称是模板定义中的依赖表达式,在实例化模板特化之前不会发生最终查找,在这种情况下,后续声明可能会影响结果查找。)
所有(!)ADL会在尝试匹配函数调用表达式中的 unqualified-id 时扩展搜索的名称空间,以包含与函数调用表达式的参数相关的名称空间。 / p>
答案 3 :(得分:1)
C ++标准定义了每个包含文件将引入的名称,但是它并没有告诉只有那些将是可用的名称。
这意味着,理论上,仅包含<vector>
可以提供std::map
。
这很不幸,因为
由于缺少包含文件而导致错误的代码无论如何都可以编译,因为特定实现中包含文件之间存在不可移植的依赖关系。
如果您的任何名称也是std
中的名称,则可能因ADL而导致查找问题。这也可能表现为可移植性问题。
明确回答你的问题:ADL只会引用已经看过的包含文件,但是你无法知道它们是哪一个,因为在一个实现中,允许标准文件包含另一个标准文件。
所以ADL MAY 查看所有可能的标准标题,但你不能指望它。
答案 4 :(得分:0)
编译器通常在单个翻译单元上工作 - 这是预处理器对其进行传递后输入中的所有源代码。此时,所有标头都已递归扩展。问题是当你包含一个给定的库头文件时,你不能假设它包含的其他文件等等。你可以随时检查,但我很确定这是一个“实现细节”。