Why is my log in the std namespace?
In the code below, I define a trivial log
function. In main
I try not to call it; I call std::log
. Nevertheless, my own log
is called; and I see "log!" on screen. Does anyone know why? I use G++ 4.7 and 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;
}
C++ Standard 17.6.1.2 paragraph 4 (emphasis mine):
Except as noted in Clauses 18 through 30 and Annex D, the contents of each header
cname
shall be the same as that of the corresponding headername.h
, as specified in the C Standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespacestd
. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespacestd
by explicit using-declarations (7.3.3).
g++ does it the latter way so that some of the same header files can be reused for C and C++. So g++ is allowed to declare and define double log(double)
in the global namespace.
Section 17.6.4.3.3 paragraphs 3 and 4:
Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with
extern "C"
linkage, both in namespacestd
and in the global namespace.Each function signature from the Standard C library declared with external linkage is reserved to the implementation for use as a function signature with both
extern "C"
andextern "C++"
linkage, or as a name of namespace scope in the global namespace.
And up at the top of Section 17.6.4.3 paragraph 2:
If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
You, on the other hand, may not declare or define ::log
in any way.
It's too bad the g++ toolchain doesn't give you any error messages, though.
What happens, I expect, is that std::log
simply delegates to ::log
. Unfortunately, ::log
only provides a float
overload, and you kindly provide a double
overload, making yours a better match. But I still don't see how it even gets considered in the overload set.
On libstdc++'s cmath
you will see this:
using ::log;
So it's bringing in the math.h functions from the global namespace into std
. Unfortunately you are supplying an implementation for double log(double)
, so the linker will not use the one from the math lib. So definitely a bug in libstdc++.
EDIT: I claim it's a bug in libstdc++ because std::log
should not suffer from interferences with the C library when you are explicitly asking for the std::
versions. Of course, this way to override standard library functions is an old "feature" from the C language.
EDIT 2: I found out that the standard doesn't actually forbid bringing names from the global namespace into std
. So not a bug after all, only a consequence of the implementation details.