以下c ++代码无法编译:
int main() {
double a = abs(5.1);
return 0;
}
它抱怨当然没有定义abs
。但以下编译:
#include <iostream>
int main() {
std::cout << abs(5.1) << std::endl;
std::cout << abs(-5.1) << std::endl;
return 0;
}
输出两个5(不是5.1)。由于很多原因,这很糟糕。首先,abs
是一种自然而常见的功能,我一直使用它,但int
部分几乎不是我想要的。其次,我(或使用我的代码的人)很容易写abs
并且没有注意到它编译但做错了,因为我(他们)非常擅长忽略警告。第三,我很明白不明白为什么iostream无论如何都要定义abs
函数。第四,我真的不明白为什么它会进入全局命名空间。
有什么方法可以防止这个令人反感的abs
函数进入我的全局命名空间?
如果重要,我正在使用
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.6)
答案 0 :(得分:11)
最有可能iostream
包括stdlib.h
来完成其部分工作。这是标头的C版本,仅在全局命名空间中为abs
声明int
(在C中,您必须使用fabs
来表示double
值。
我不知道有任何具体方法可以让abs
不被包含在内,但我知道g ++ 4.5 很多更好的是没有基本带来的多余东西包括iostream
和string
。
也可能会收到一条警告,指出double被截断为int(编辑:是的,使用-Wconversion
来警告)。
答案 1 :(得分:4)
在C中,包括一个标准标题是不允许其行为,因为它包含任何其他标准标题。这样可以避免您遇到的问题,而且难以实施。
C ++允许任何标准头包含任何其他标准头。这使得实现变得相当容易,但是可能会导致你看到的那种问题,其中包括一个看似无关的标题使得一个函数可见而你真的不想使用,而不是因为函数而得到错误你使用的根本没有声明。
不幸的是,我认为没有一种简单的方法可以解决这个问题。虽然很容易想象<iostream>
独立于<stdlib.h>
,但更容易看出它可能需要/想要ios_base
之类的定义。在允许后者的同时定义禁止前者的事情还需要相当多的额外工作。
答案 2 :(得分:1)
如果这是一个持续的维护问题,为什么不在程序开头添加一些专门检查abs()
问题的代码?
// test if abs() is defined incorrectly, as would happen if <stdlib.h> were
// included by <iostream>. abs() it should return a float/double, not an int
// (put suggestions here how to fix problem)
if (abs(-5.1) == 5)
{
std::cerr << "Invalid build: abs() defined improperly, ..." << std::endl;
return 2; // exit program by returning from main
}
这将使警告被忽视更加困难。