C++ 为什么我的日志位于std名称空间中?
在下面的代码中,我定义了一个普通的C++ 为什么我的日志位于std名称空间中?,c++,namespaces,overloading,C++,Namespaces,Overloading,在下面的代码中,我定义了一个普通的log函数。在main中,我尽量不调用它;我调用std::log。然而,我自己的log被调用;我在屏幕上看到“日志”。有人知道为什么吗?我使用G++4.7和clang++3.2 #include <iostream> #include <cmath> double log(const double x) { std::cout << "log!\n"; return x; } int main(int argc, char
log
函数。在main
中,我尽量不调用它;我调用std::log
。然而,我自己的log
被调用;我在屏幕上看到“日志”。有人知道为什么吗?我使用G++4.7和clang++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;
}
#包括
#包括
双对数(常数双x){std::cout我想发生的是,std::log
只是委托给::log
。不幸的是,::log
只提供了一个float
重载,而您可以提供一个double
重载,使您的重载更加匹配。但我仍然不知道它在重载集中是如何被考虑的。在libstdc++的cmath
上,您将看到以下内容:
using ::log;
因此,它将全局名称空间中的math.h函数引入到std
。不幸的是,您正在为双日志(double)
提供一个实现,因此链接器将不会使用math库中的函数。因此libstdc++中肯定存在一个bug
编辑:我声称这是libstdc++中的一个bug,因为当您明确要求使用std::
版本时,std::log
不应该受到C库的干扰。当然,这种覆盖标准库函数的方法是C语言的一个老“特性”
编辑2:我发现该标准实际上并不禁止将全局名称空间中的名称带入std
。因此,这毕竟不是一个bug,只是实现细节的结果。C++标准17.6.1.2第4段(重点):
除了第18至30条和附录D中所指出的,每个标题<代码> cNe>代码>与相应的标题<代码>名称> h <代码>相同,如C标准库(1.2)或C++ unicode TR中所规定的,如包含的内容。(在C中定义为宏的名称除外)位于命名空间
std
的命名空间范围(3.3.6)内。未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明(7.3.3)注入命名空间std
。
G+++是这样的,所以可以将某些头文件重新用于C和C++。因此,G+允许在全局命名空间中声明和定义<代码>双日志(double)< /C> >
第17.6.4.3.3节第3段和第4段:
使用外部链接声明的标准C库中的每个名称都保留给实现,以便在命名空间std
和全局命名空间中用作带有extern“C”
链接的名称
使用外部链接声明的标准C库中的每个函数签名保留给实现,以用作extern“C”
和extern“C++”链接的函数签名,或用作全局命名空间中命名空间范围的名称
在第17.6.4.3节第2段的顶部:
如果程序在保留名称的上下文中声明或定义名称,而不是本子句明确允许的名称,则其行为是未定义的
另一方面,您不能以任何方式声明或定义::log
工具链没有给你任何错误消息,但是.C++中的< p>,编译器可以在全局命名空间中实现C库并委派给它(这是实现定义)。
17.6.1.2.4除非第18条至第30条和附录D中另有说明,否则每个标题cname的内容应相同
与C标准库(1.2)或C Unicode中规定的相应标题名.h相同
TR,如适当,如包含。在C++标准库中,声明除外(除了
C)中定义为宏的名称在名称空间标准的名称空间范围(3.3.6)内。
未指定这些名称是否首先在全局名称空间范围内声明,然后注入
通过显式使用声明(7.3.3)导入命名空间std
一般来说,我避免使用与C标准库相同的签名来创建函数。C++标准当然会给编译器提供使用这些签名的自由,如果选择的话,这意味着如果你尝试使用相同的签名,你可能会与编译器抗争。因此,你得到了奇怪的结果。
不过,我预计会出现链接器错误或警告,我认为这可能值得报告
[编辑]
哇,ninja'd.因为您已经在全局名称空间中重写了它。如果您不想使用更安全、更干净的语言,例如,使用名称空间可以避免这种危险
:
听起来像是一个严重的编译器错误…我可以在Macports下的g++4.6上重现这个错误。但在g++4.2或4.4中不会发生这种情况。从这两种情况来看,我会说std::log()函数调用log()。但它会生成一个错误/警告,指出您的文件重新定义了日志或类似的内容。这很有趣。我甚至可以在ideone上复制它……我想自己知道答案。@ColeJohnson:这就是为什么您使用名称空间。并非所有内容都需要在一个类中。就我个人而言,我将所有内容都放在名称空间中,除了main
.
需要提供log(double)
。我在MSVC10上也期望得到同样的结果,我最终在链接上得到了一个重复的符号错误,但只是在3到4次重建之后。@aschepper:
需要提供double std::log(double)
(我把重点放在名称空间上是一件大事,因为现在正是如此)。该标准要求它们位于::std
命名空间中,如果它们选择,每个实现都可以在全局命名空间中自由定义它们。@DeadMG:你不是说::log
(C库函数)提供了一个双p
#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