<algorithm> 是否包括 <cmath>?

Does <algorithm> include <cmath>?

以下程序编译正确:

#include <algorithm>

int main(int argc, char *argv[]) {

    return int(log(23.f));

}

(在带有标志 -std=c++11 的 g++ 4.9.2 下)

该代码使用函数 log,该函数在 <cmath> 上定义。但是,它不包括 header <cmath>,仅包括 header <algorithm>。为什么 g++ 没有给出任何警告,并正确编译代码?

根据标准,某些 headers 确实包括其他一些。例如,<cinttypes> 包括 <cstdint>。请参阅 Includes 部分 here. With respect to <algorithm>, there is no such statement as to which other headers it should include (see here)。因此,结论是,<algorithm> 不需要包含 <cmath>,并且您的示例代码不可移植。它可能无法在其他 C++ 实现上编译。

在 C++11 标准中,[res.on.headers]/1 指出

A C++ header may include other C++ headers. A C++ header shall provide the declarations and definitions that appear in its synopsis. A C++ header shown in its synopsis as including other C++ headers shall provide the declarations and definitions that appear in the synopses of those other headers.

现在考虑 [algorithms.general]/2:

Header <algorithm> synopsis

#include <initializer_list>

namespace std {
  // ......

<cmath> 未列出且显然未包含在 <initializer_list> 中。因此,您的程序不能保证在 standard-conforming 实现上编译。永远不要依赖“隐含包含”——一般准则是包含使用实体的每个 header。
例外情况是<iostream> 包括 <ostream>,自 C++11 起得到保证。

回答你的问题:

Why is it that g++ doesn't give any warnings, and compiles the code correctly?

因为不需要 C++ 实现,而且考虑到 #include 的工作方式,实际上很难实现此警告。 Attempts已经完成,但还有一些问题没有完全解决。


移动到 different model 可以启用这种检查。但是,为了向后兼容并允许最简单的转换,我使用的标准库 'modularizations' 碰巧明确允许以前依赖于间接包含的代码继续工作。

你可以看到这个,例如,在 libc++ 的 module map;那些 export * 行声明 "any modules imported by this module are also exported." 也就是说,导入模块 std.cmath 的模块 std.algorithm 也导出,因此导入 std.algorithm 的任何人也可以访问std.cmath.

对于新代码,如果可以关闭这些 'legacy exports' 会非常好,但是对于预先存在的大型项目,能够打开 -fmodules 并让项目工作是非常好的没有变化。


使用 clang 的 libc++ 模块实现,并修改模块映射文件以删除不可移植的间接包含行为,clang 报告如下错误:

main.cpp:5:16: error: declaration of 'log' must be imported from module 'Darwin.C.math' before it is required

return int(log(23.f));
           ^  

/usr/include/math.h:387:15: note: previous declaration is here

extern double log(double);  
              ^  

1 error generated.

libc++ <algorithm> 不包含 <cmath>,所以我用 <random> 代替。否则产生上述内容的来源与您显示的相同。