【发布时间】:2014-11-06 23:33:10
【问题描述】:
C++ 语言标准在 D.5
中说2 每个 C 标头(每个标头都有一个
name.h形式的名称)的行为 好像每个名称都由 对应的cname标头放置在全局命名空间内 范围。未指定这些名称是首先声明还是 在命名空间std的命名空间范围 (3.3.6) 内定义,并且是 然后通过显式注入全局命名空间范围 使用声明(7.3.3)。3 [示例:标题
<cstdlib>确保在 命名空间std。它还可以在全局范围内提供这些名称 命名空间。标题<stdlib.h>肯定提供相同的 全局命名空间中的声明和定义,就像在 C 标准。它还可以在命名空间中提供这些名称std。 —结束示例]
这似乎相当明确地声明(“...每个名称...”,“...相同的声明...”)旧式 <name.h> 标头必须提供与新样式的<cname> 标头,但在全局命名空间中。例如,各种 C 函数的 C++ 特定重载版本也不例外。
这似乎意味着<math.h> 必须在全局命名空间中提供sin 函数的三个版本:sin(float)、sin(double) 和sin(long double)。反过来,这意味着以下 C++ 代码应该无法通过重载解析
#include <math.h>
int main() {
sin(1);
}
在 MSVC++ 编译器下确实失败,但在 GCC 和 Clang 下编译成功。那么,GCC 是否只是忽略了关于已弃用的旧式标头的标准要求?还是我以某种方式误解了标准中的措辞?
【问题讨论】:
-
第 17.6.2.3.1 节允许实现将
extern "C"链接到使用外部链接声明的 C 标准库中的名称(尽管它建议不要这样做)。如果一个实现这样做了,它就不能定义三个不同版本的sin()。 -
我想你的意思是说
必须提供三个版本。 . .因为 math.h 是 C 头文件。因此,考虑到这一点,不会有任何过载问题,因为只有一个 sin 版本,但 std::sin 有三个。 -
@iheanyi:头文件可以很容易地在 C 和 C++ 之间进行交叉编译。如果没有其他办法,
#ifdef __cplusplus总是可以挽救这一天。 -
是和不是。您不能包含
然后使用 std::sin,因为它在 math.h 中不存在。 #ifdef __cplusplus 与否。 -
@iheanyi:呃……这和
std::sin有什么关系?首先,问题是关于math.h中的sin,而不是关于std::sin。其次,即使不是主题,C++ 标准实际上声明math.h允许在命名空间std中额外提供这些名称(参见上面的标准引用)
标签: c++ legacy standard-library