isnan 是否在 std:: 命名空间中?更一般地说,何时是 std::必要、可选或要避免



在 Mingw 4.7.2 中,我有一个由于调用 isnan 而无法编译的库。如果我使用 std::isnan,编译器会说"一切都会好起来的",而且我确实设法编译了我的文件。

但是如果我在这里检查(编辑:但也许我也应该在这里检查:-((,std::似乎没有必要。如果我添加它,文件是否可移植?

更一般地说,对于每种情况,是否有一种通用方法来了解何时需要放置std::(为了可移植性(、可选或避免?

编辑

事实上,问题的起源之一是有多个标头包含,并且一些包含的标头包含<cmath>,而此cpp文件试图包含<math.h>(当<cmath>已被包含时(。

这取决于您包含的标头。如果包含 C 标头<math.h>(它是C++的一部分,尽管标记为已弃用(,则可以使用非限定的 C 函数,如 isnan 。另一方面,如果您包含 C++ 标头<cmath> ,则只能保证它将<math.h>中的所有函数带入std命名空间,因此您必须正确限定它们,例如std::isnan(或使用某种using指令(。不幸的是,当包含<cmath>时,也允许不需要将这些函数引入全局命名空间(因此它是众多"在我的机器上工作">之一 - C++的发生率以及许多人编写代码的原因,就像你刚刚尝试编译失败一样

(。

所以总结一下:要么包括<math.h>并使用isnan要么包括<cmath>并使用std::isnan,其他一切都是不可移植的。当然,所有这些都适用于任何其他 C 标头及其各自的 C++ 版本。

编辑:应该注意的是,这个特定的功能isnan仅从C++11开始受支持,并且在C++98中根本不可用(这可能是您混淆的一部分(。但这在这种情况下不会改变任何事情,因为在 C++98 中,<cmath><math.h>(这是当时实际的 C89/C90 标头,而不是 C++11 包含的 C99 标头(都没有此功能,因为它们始终同步。因此,您问题中的这个库可能尝试的是使用 C++98,同时从不同的 C99 实现中获取isnan函数(这不是一个特别好的主意,因为它可能与 C++ 实现的 C89/C90 部分冲突,甚至从未尝试过这个(。

C 没有命名空间的概念。当你写#include <math.h>头中声明的所有名称都会进入全局命名空间,你需要写isnan

C++具有命名空间。尽管如此,当你写#include <math.h>标头中声明的所有名称都会进入全局命名空间,你需要写isnan,就像在 C 中一样。

此外,当你写#include <cmath>标头中声明的所有名称都会进入命名空间std,你需要写std::isnan

此外,C++实现也可以走另一条路,#include <math.h>将名称放入std和全局命名空间中,#include <cmath>将名称放入全局命名空间以及std中。不要依赖这个;这样做的代码不可移植。这是对实施者的让步,使事情变得更容易;它的真正含义是,如果您使用#include <cmath>则不能假设全局命名空间中不会有isnan,并且如果您使用#include <math.h>则不能假设std中不会有isnan

那是因为isnan来自C.使用不同类型的include会导致不同的结果。以 C 标头<math.h>中的isnan为例:

如果使用 #include <cmath> ,它将放在 std 命名空间中。

如果使用 #include <math.h> ,它将放在全局命名空间中。

C++11 D.5 C 标准磁带库接头

每个 C 标头(每个标头都有一个 name.h 形式的名称(的行为就像由相应的 cname 标头放置在标准库命名空间中的每个名称都放置在全局命名空间范围内一样。未指定这些名称是首先在命名空间 std 的命名空间范围 (3.3.6( 内声明或定义,然后通过显式 using-声明 (7.3.3( 注入全局命名空间范围。

[ 示例:标头确保在命名空间 std 中提供其声明和定义。它还可以在全局命名空间中提供这些名称。标头确保在全局命名空间中提供与 C 标准相同的声明和定义。它还可能在命名空间 std 中提供这些名称。

最新更新