为什么在 C++ 中使用 "using namespace std;" 处理 double 时会产生不同的结果?

4
今天,我试图回答这篇文章(关于如何检查是否可以构造一个三角形),但是遇到了奇怪的结果。
使用测试数据15.15 35.77 129.07,这段代码:
#include <iostream>
using namespace std;

const double e = 0.000001;

void f(double a, double b, double c)
{
    if (abs(180 - (a+b+c)) > e) {cout << "test"; }
}

int main()
{
    double a,b,c; cin >> a >> b >> c;
    f(a,b,c);
}

正常打印test,而这个:

#include <iostream>
const double e = 0.000001;

void f(double a, double b, double c)
{
    if (abs(180 - (a+b+c)) > e) {std::cout << "test"; }
}

int main()
{
    double a,b,c; std::cin >> a >> b >> c;
    f(a,b,c);
}

不会。唯一的区别在于using namespace std;这一行(当我将using namespace std;添加到第二段代码中时,如预期般正常运行)。
我阅读了很多关于using namespace std;的帖子: 但似乎using namespace std;的唯一作用是为了简化编码,换来偶尔会出现类/变量/命名空间名称冲突的情况(当讨论是否使用它时,这一点被提起得最多)。
我找到了1篇相关帖子: 为什么g++(4.6和4.7)会将此除法的结果提升为double?我能停止它吗?,但在其他地方没有找到更多信息。
那么这里我错过了什么?
—一些机器信息: - Windows 10, 64位 - Code::Blocks 20.03 - gcc/g++ 6.3.0

2
就此而言,你的代码存在未定义行为。abs不在<iostream>中,而且你还没有包含想要使用abs的头文件。很可能你正在调用不同的函数,或者甚至是宏而不是函数。 - NathanOliver
1
我的机器无法编译第二个示例,缺少'abs'。我添加了#include<cmath>并将abs更改为std::abs。它打印出了“test”。 - Eljay
1
@YSC · 因为它们不完整(约50%的标准C++头文件),所以还没有准备好使用。 我还没有在GitHub上分享。 我称我的项目为“deader files”,因为它们只是桩而没有太多实现。constexpr也让我困扰,因为它们不支持编译时评估。它们仅适用于C ++14,因为这是我目前正在使用的版本(不是我选择的,我更愿意暂时转移到C ++17,尽快转移到C ++20...但我的项目卡在了C ++14)。 - Eljay
1
在示例代码中避免用户输入通常是一个好主意。根据采纳的答案,我想你没有尝试将 double a,b,c; std::cin >> a >> b >> c; 替换为 double a = 15.15, b = 35.77, c = 129.07; 吧?这不仅使得重现结果更容易,也消除了 namespace std 可能出现的一处问题。 - JaMiT
@JaMiT 是的,我会注意到的。谢谢你的建议! - silverfox
显示剩余4条评论
2个回答

7

您存在名称冲突: int abs(int)double std::abs(double)

使用using namespace std;abs(180 - (a+b+c)) 会找到两个函数,而std::abs是更好的匹配。

不使用using namespace std;abs(180 - (a+b+c)) 只会找到前者,需要进行类型转换到int,因此出现了观察到的行为。

实际需要的是:

#include <iostream>
const double e = 0.000001;

void f(double a, double b, double c)
{
    if (std::abs(180 - (a+b+c)) > e) {std::cout << "test"; }
}

int main()
{
    double a,b,c; std::cin >> a >> b >> c;
    f(a,b,c);
}

2
请注意,您还可以使用 std::fabs 来明确记录您的意图,并非使用整数版本。 - YSC
啊,我明白了。所以我找到的那篇文章在这个情况下是正确的。我一直很困惑。 - silverfox

1
这是因为你没有在 abs() 前加上 std::,所以编译器不确切知道哪个函数被调用,导致了未定义行为。它很可能找到并使用了适用于 int 参数的 C 函数版本。

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