I have a question regarding function declaration scopes in C++. Suppose using #include <cmath>
introduces a function symbol into the global namespace. According to my understanding, in principle, it should only introduce symbols into the std
namespace, but in practice, from my own experience, some symbols appear in the global namespace. This answer seems to confirm this: cmath header confusion.
Now, what happens when I declare a function (with the same prototype as the function from the global namespace) inside a namespace foo { }
? Suppose for example, that sqrt()
from <cmath>
ends up in the global namespace, and I have:
#include <cmath>
namespace foo {
template <class T>
T sqrt( T x ) {
// do something extra...
return std::sqrt( x );
}
}
// ...
void foo::bar() {
double a = 4.0;
double b = sqrt( a );
}
The template is resolved to the symbol double sqrt( double x )
, which seems like it should clash with the one in the global namespace. It seems to work, but is this generally a bad practice?
More generally, does a function declared inside a namespace take precedence over a global function, when used from inside the same namespace? Does this violate the C++ standard in any way?
There are two separate issues here.
Firstly, it is true that pulling in certain headers injects symbols both in the global namespace, and in the std
namespace. This sausage-making has to do with C++'s legacy, and roots, in C; and to try to have a good chance of getting legacy C code compilable in C++ with as little pain as possible.
Secondly, is is true that...
a function declared inside a namespace take precedence over a global function, when used from inside the same namespace?
That is correct. And, no, this does not
violate the C++ standard in any way?
In fact, the C++ standard explicitly specifies that this is how things should work. Resolving a reference from a namespace first searches the same namespace, as the first order of business. Then the parent namespace, in case of a nested namespace. Then, eventually, the global namespace.
Then, using namespace
makes things complicated. Which is why you should not do that.
And then finally, to make things interesting, there's also argument dependent lookup that turns all these rules on their heads by searching for a function not in the current namespace, the parent namespace, or a global namespace, but in the same namespace as the functions' arguments.
Nobody has ever accused C++ of being simple.