Given this, consider the following C++ program:
#include <cstdio>
#include <cmath>
namespace foo
{
inline double sqrt(double x)
{ std::printf("sqrt(%g) called\n", x); return std::sqrt(x); }
}
using foo::sqrt;
int main()
{
std::printf("hello, world\n");
std::printf("std::sqrt(2.0) = %g\n", std::sqrt(2.0)); // call #1
std::printf("foo::sqrt(2.0) = %g\n", foo::sqrt(2.0)); // call #2
std::printf(" sqrt(2.0) = %g\n", sqrt(2.0)); // call #3
}
Since including <cmath> doesn't put anything into the global namespace,
then if my understanding is correct, the only sqrt() function visible
in the global namespace at the call site of of call #3 is the one imported
from namespace foo using the using declaration. Since there is only a
single sqrt() function visible at the call site, it follows that call #3
is unambiguous (and hence is valid).
Unfortunately, my compiler (g++ 4.2.4, OpenBSD 4.6-stable) disagrees:
% /usr/local/bin/g++ -W -Wall -o overload overload.cc
overload.cc: In function 'int main()':
overload.cc:18: error: call of overloaded 'sqrt(double)' is ambiguous
/usr/include/math.h:161: note: candidates are: double sqrt(double)
overload.cc:6: note: double foo::sqrt(double)
%
g++ 4.3.2 on a Red Hat Enterprise Linux 5.3 system gives a similar error
(albeit with a strange garble-character for the function name):
% /usr/bin/g++43 -W -Wall -o overload overload.cc
overload.cc: In function ?:
overload.cc:18: error: call of overloaded ? is ambiguous
/usr/include/bits/mathcalls.h:157: note: candidates are: double sqrt(double)
overload.cc:6: note: double foo::sqrt(double)
%
Can someone explain to me what's going on here? In particular, can
someone explain to me how it is that after
#include <cstdio>
there is a function
double sqrt(double)
in the *global* namespace?
thanks, ciao,
--
-- "Jonathan Thornburg [remove -animal to reply]" <jth...@astro.indiana-zebra.edu>
Dept of Astronomy, Indiana University, Bloomington, Indiana, USA
"Washing one's hands of the conflict between the powerful and the
powerless means to side with the powerful, not to be neutral."
-- quote by Freire / poster by Oxfam
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
It might, or it might not. :-(
Many (most?) compilers are not so strict about this. If the C++
compiler is built on top of an existing C library, the global C
functions might be visible at this point.
This is so common that the upcoming C++0x standard allows this
practice, and says that it is unspecified whether the functions are in
the global namespace, or not.
Bo Persson
--
That's what the current standard says. It's impractical at best, and
C++0x accepts reality by removing the prohibition on C++ headers
declaring C names in the global namespace:
#include <cmath>
declares:
double std::sqrt(double x);
and might declare
double sqrt(double x);
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)
<snip></snip>
>
> Unfortunately, my compiler (g++ 4.2.4, OpenBSD 4.6-stable) disagrees:
<snip></snip>
In the documentation for the "GNU C++ Library" it says
(http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch03s02.html):
"The standard specifies that if one includes the C-style header (<math.h>
in this case), the symbols will be available in the global namespace and
perhaps in namespace std:: (but this is no longer a firm requirement.)
One the other hand, including the C++-style header (<cmath>) guarantees
that the entities will be found in namespace std and /perhaps in the global
namespace/." (My emphasis)
I am not near my copy of the standard in order to be able to support this with a
reference, but it seems that gcc is following the above. What this seems to be
saying is that the standard doesn't require that the addition of the <math.h>
function sqrt to the std namespace under <cmath> thereby precludes its being
also available in the global namespace via the same inclusion.
You can see the same occurring in the example you give with regard to printf
also, which doesn't cause the compile to fail if you omit any one of your std::
qualifiers.
Regards
Paul Bibbings
--
Ick. This seems to remove a big chunk of the benefits which <cmath>
originally claimed to offer over <math.h>. :(
Is there any way (as a programmer writing C++ source code which may
be compiled in a C++0x environment) to get std:: names while ensuring
that I don't get the global-namespace ones?
Also, just out of morbid curiosity, what is including <math.h> specified
as doing in C++0x?
thanks, ciao,
--
-- "Jonathan Thornburg [remove -animal to reply]" <jth...@astro.indiana-zebra.edu>
Dept of Astronomy, Indiana University, Bloomington, Indiana, USA
"Washing one's hands of the conflict between the powerful and the
powerless means to side with the powerful, not to be neutral."
-- quote by Freire / poster by Oxfam
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
Not really. You could possibly hide the effect by putting your own
code in your own namespace.
>
> Also, just out of morbid curiosity, what is including <math.h>
> specified as doing in C++0x?
>
Including <math.h> provides the declarations in the global namespace.
According to C++98 this should be done as-if first declaring them in
namespace std and then providing a lot of using-declarations. C++0x
doesn't require this machinery, so you for example can use existing,
system provided, C headers.
Including <cmath> provides the declarations in namespace std. C++98
required that the functions were declared in namespace std only, but
many compilers chose to, or had to, use C headers and import the names
into namespace std with using declarations. C++0x approves of this (or
documents it as a de facto standard, depending on how you see it).
Bo Persson
--
One way to get them out of the global-namespace is to craft some files
that puts them into a namespace (similar to what you did with your
version in foo):
Write a "cmath.h" file as follows:
#ifndef CMATH_H
#define CMATH_H
namespace pseudostd
{
double sqrt(double x);
}
#endif
Then a cmath.cpp file:
#include "cmath.h"
#include <math.h>
double pseudostd::sqrt(double x) { return ::sqrt(x); }
Then in your program you can:
#include "cmath.h"
int main()
{
pseudostd::sqrt(2.0); // works
sqrt(2.0); // compiler error
return 0;
}
If you are feeling bold, you could replace "pseudostd" with "std".
That may give you behavior closer to what you wanted out of <cmath>.
Although it is technically undefined to add to std in such a way, it
will probably work.
Another simpler approach that works on some compilers (MSVC++6.0, g++
3.4.4, but not MSVC++9.0)
In your program, instead of:
#include <cmath>
you could use:
namespace std
{
#include <math.h>
}
--