11

使用 Mingw 4.7.2,我有一个由于调用isnan. 如果我使用,编译器会说“一切都会好起来的”std::isnan起来的” ,实际上我设法编译了我的文件。

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

更一般地说,对于每种情况,是否有一种通用的方法来理解何时放置std::是必要的(为了便携性)、可选的或应该避免的?

编辑

实际上,问题的根源之一是包含多个标头,并且一些包含的标头 include <cmath>,而此 cpp 文件尝试包含<math.h>(当<cmath>已经包含时)。

4

3 回答 3

18

这取决于您包含哪个标题。如果您包含 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,同时isnan从不同的 C99 实现中获取函数(这不是一个特别好的主意,因为它可能与 C++ 实现的 C89/C90 部分冲突,虽然从未尝试过)。

于 2013-08-08T14:43:41.997 回答
5

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>,你不能假设isnanstd.

于 2013-08-08T15:10:34.370 回答
3

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

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

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

C++11 D.5 C 标准库头文件

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

[ 示例:标头确实在命名空间 std 中提供了它的声明和定义。它还可以在全局命名空间中提供这些名称。头文件在全局命名空间中确实提供了相同的声明和定义,就像在 C 标准中一样。它还可以在命名空间 std 中提供这些名称。—结束示例]

于 2013-08-08T14:42:42.953 回答