在下面的代码,我定义了一个简单的log
功能。 在main
我尽量不把它; 我打电话std::log
。 不过,我自己的log
被调用; 我看到“登录!” 在屏幕上。 有谁知道为什么吗? 我用G ++ 4.7和铛++ 3.2。
#include <iostream>
#include <cmath>
double log(const double x) { std::cout << "log!\n"; return x; }
int main(int argc, char *argv[])
{
std::log(3.14);
return 0;
}
C ++标准17.6.1.2第4(重点煤矿):
除了通过30和附件d如项18所指出的,每一个报头的内容cname
应是相同的与对应的标题的name.h
,如在C标准库(1.2)或C- Unicode的TR指定,如适当,仿佛被列入。 在C ++标准库,但是,声明(除了其被定义为在C宏名称)是命名空间的命名空间范围(3.3.6)内std
。 它是不确定是否这些名称是全局命名空间范围内的第一个声明,然后注入到命名空间std
通过明确的使用申述 (7.3.3)。
克++做它后者方式,使一些相同头文件可以为C和C ++进行再利用。 因此,G ++允许声明和定义double log(double)
在全局命名空间。
第17.6.4.3.3第3和4:
从外部链接声明的标准C库中的每个名称被保留,以用作同一个名字的实施extern "C"
联动,无论是在命名空间std
,并在全局命名空间。
从外部链接声明的标准C库的每个功能的签名被保留到实现用作具有两种功能:签名extern "C"
和extern "C++"
联动,或在全局命名空间的命名空间范围的名称。
而在达第17.6.4.3条第2款的顶部:
如果程序声明或在它是保留一个上下文定义了一个名字,除了由于明确本条款允许的,其行为是不确定的。
而你,另一方面,可能不声明或定义::log
以任何方式。
这太糟糕了G ++工具链不给你任何错误消息,但。
会发生什么,我希望是, std::log
干脆委托给::log
。 不幸的是, ::log
只是提供了一个float
过载,你请提供一个double
过载,使你更好的匹配。 但我还是不明白如何它甚至获取重载集合考虑。
上的libstdc ++的cmath
你会看到:
using ::log;
因此它带来的math.h中的功能从全局命名空间为std
。 不幸的是你提供了一个实现double log(double)
,因此链接器将不使用来自数学lib中的一个。 所以肯定是在的libstdc ++的错误 。
编辑:我要求它在一个的libstdc ++的bug,因为std::log
不应与C库干扰,当你明确要求对遭受std::
版本。 当然,这种方式重写标准库函数是C语言的一个古老的“功能”。
编辑2:我发现,该标准实际上并不禁止将名称从全局命名空间为std
。 所以,毕竟不是一个错误,只有实现细节的结果。
在C ++中,编译器就可以实现在全局命名空间的C库,并委托给它(这是实现定义)。
17.6.1.2.4通过除30和附件d如项18所指出的,每一个报头的CNAME的内容应是相同于相应的头name.h的,如在C标准库SPECI音响ED(1.2)或C- Unicode的TR,在适当时,如果被列入。 在C ++标准库,但是,声明(除了其是定义为在C宏德音响名称)是命名空间std的命名空间范围(3.3.6)内。 这是unspeci网络版是否这些名字第一个全局命名空间范围内声明的,然后通过使用明确的-声明 (7.3.3) 注入空间std。
在一般情况下,我会避免函数具有相同签名的C标准库之一。 C ++标准当然给编译器可以自由地使用这些特征如果选择这种方式,这意味着如果你尝试使用相同的签名,你可能会打你的编译器。 因此,你得到奇怪的结果。
我希望链接错误或警告,虽然,我认为这可能是值得我们举报。
[编辑]
哇,ninja'd。
因为你已经在全局命名空间覆盖它。 使用命名空间避免了危险的,如果你不想要移动到像一个更安全,更清洁的语言稔的例子。
正确使用命名空间演示 :
#include <iostream>
#include <cmath> // Uses ::log, which would be the log() here if it were not in a namespace, see http://stackoverflow.com/questions/11892976/why-is-my-log-in-the-std-namespace
// Silently overrides std::log
//double log(double d) { return 420; }
namespace uniquename {
using namespace std; // So we don't have to waste space on std:: when not needed.
double log(double d) {
return 42;
}
int main() {
cout << "Our log: " << log(4.2) << endl;
cout << "Standard log: " << std::log(4.2);
return 0;
}
}
// Global wrapper for our contained code.
int main() {
return uniquename::main();
}
输出:
Our log: 42
Standard log: 1.43508