<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>
代替。否则产生上述内容的来源与您显示的相同。
以下程序编译正确:
#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>
代替。否则产生上述内容的来源与您显示的相同。