C++余弦函数可以不使用std命名空间,为什么?

7

我有一个相当大的应用程序,而且我没有使用std命名空间。我注意到我没有包含std::cos或std::sin,但我得到了正确的结果。为什么?

以下是一些简化代码示例:

#include <ctime>
#include <cmath>
#include <iostream>
#include <vector>
//#include <unistd.h>
#include <fstream>
#include <sstream>
#include <iomanip>

using std::cout;
using std::endl;

int main()
{
    double pi = 4*(atan(1));

    cout << "pi = " << pi << endl
         << "cos(pi) = " << cos(pi) << endl
         << "sin(pi) = " << sin(pi) << endl;



    return 0;
}

我已经保留了所有的头文件,在主代码中使用它们。输出结果返回了 ~3.14、-1 和 1e-16,这是预期的。为什么会这样呢?cos和sin不是在std里嘛?

我正在远程Unix服务器上使用g++编译器。

谢谢。


3
迈克·西摩的回答对您有帮助吗?https://dev59.com/XWgu5IYBdhLWcg3wxZzd - bblincoe
没错,问题解决了。谢谢 :) - Aaron
2个回答

9
当你包含<cmath>时,所有的函数都在std::中声明。对于C头文件,还有一个特殊规则,允许(但不需要)实现将它们可见于全局命名空间;这是因为大多数实现会简单地适应C头文件,类似于:
#include <math.h>
namespace std
{
    using ::sin;
    using ::cos;
    // ...
}

这是一种明显的实现库的方式,无需重写全部代码,只需要用C++重新实现,这将导致所有名称也存在于全局命名空间中。

正式地说,这是C++11的一个特性;在C++11之前,<cmath>只能将符号引入到std::中。实际上,所有或者至少大多数的实现都做了类似上述的事情,并且非法地将它们引入到全局命名空间中,所以C++11改变了标准以反映现实。


7
很遗憾,库实现允许将C库的名称转储到全局命名空间以及std中,并且很多库都这样做。更糟糕的是,在某些情况下,仅在全局命名空间中提供某些重载,如果您不指定std版本,则会导致意外的精度损失。 应始终使用std版本,但可靠的强制执行方法很少,因此您只需小心地穿过这个特定的雷区即可。

在某些情况下,只有一些重载可用这一事实是一个好的观点(我已经忘记了,尽管我曾经被它咬过)。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接