7

As I understand it, in C++03 #include <cmath> must declare the functions only in namespace std. Since C++11 they may additionally be declared in global namespace. This is the result of the practice where most C++ implementations declared the functions in global namespace (presumably #includeing <math.h>), and then just did using ::acos; etc. in namespace std.

But it seems to me that it would be similarly easy for the implementations to do something like this in their <cmath>:

namespace __C_LANGUAGE_MATH_H
{
#include <math.h>
}
// ...
namespace std
{
// ...
using __C_LANGUAGE_MATH_H::acos;
// ...
}

Why wasn't this practiced instead of just polluting the global namespace? Does my suggested solution have some major drawbacks which made the C++ committee allow pollution of global namespace in C++11?

NOTE: this does work, and linker gives no errors, at least with GCC + Binutils-ld. I've actually tried and edited GCC's cmath file like follows, and compiled my project which actively uses cmath functions successfully (after fixing some calls which mistakenly didn't specify std:: in the project):

mv /usr/include/c++/5.3.0/cmath{,.bak}
sed -i -e 's@\(# *include <math.h>\)@namespace __C_LANGUAGE_MATH_H\n{\n\1\n}@' \
    -e 's@\(using \+\)::@\1__C_LANGUAGE_MATH_H::@' /usr/include/c++/5.3.0/cmath
Ruslan
  • 18,162
  • 8
  • 67
  • 136
  • 5
    Including math.h in a namespace doesn't move the *implementations* of these functions to that namespace, so you get a linker error. In practice, some C++ implementations *had to* use the C library as a base for its functionality (not limited to math). The changes in C++11 just documented current practice. – Bo Persson Feb 20 '16 at 10:12
  • Some implementations only defined `extern "C"` versions (non-overloaded) in global namespace, as those would be unusable anyway due to presence of those names in C runtime. – Revolver_Ocelot Feb 20 '16 at 10:18
  • 1
    @BoPersson: Why a comment and not an answer? – Christian Hackl Feb 20 '16 at 10:18
  • @BoPersson why linker error? If they are `extern "C"`, which they should be, they still have unmangled names, and are only referenced _in user source_ through namespace. For linker they still look like good old unmangled C names. At least it's so for GCC in Linux. I have actually tried to edit GCC's `cmath` file and got good results. – Ruslan Feb 20 '16 at 10:26
  • You mention the behavior was changed in standard. Have you looked at corresponding [defect report](http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456)? The problem is this approach is impractical since c++ standard library is built on top of maybe independent c library and was not followed anyway. Say `cstdio` need to provide `EOF`, `BUFSIZE`, `FOPEN_MAX` macros that can only be done reliably by including c library headers. – dewaffled Feb 20 '16 at 14:02
  • @frymode that's not a problem if the headers are included into a separate namespace, as I suggested in my example code. – Ruslan Feb 20 '16 at 14:09
  • @Ruslan You'll still need to deal with say `::FILE` (by including ``) and `std::FILE` (by including ``) types difference. I also found [issue discussion](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=6257) in gcc bugzilla - they tried different approaches but in the just left it as it is. – dewaffled Feb 20 '16 at 14:14

2 Answers2

2

As stated in corresponding issue discussion in gcc bugzilla this approach will not allow including C header after C++ because of include guards:

#include <cmath>
#include <math.h> // include skipped by include guards

...
sin(x); // error: no sin in global namespace

As you mentioned standard requirements to C library wrappers were changed after issue was posted in defect report and previous requirements have been declared impractical from implementation point of view.

dewaffled
  • 2,850
  • 2
  • 17
  • 30
-1

They don't do it that way because it doesn't work. Try it. There's no function in the C library named __C_LANGUAGE_MATH::acos.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • It will work since `acos` declared as `extern "C"` in `math.h` causing it to be linked unmangled. – dewaffled Feb 20 '16 at 14:49
  • @frymode - sure, if the standard C headers all had `extern "C"` everywhere the problem would be easy. But they don't, and C++ library implementors often don't have control over those C headers. – Pete Becker Feb 20 '16 at 14:54
  • 2
    They should - otherwise c++ mangling would be applied and they won't link. – dewaffled Feb 20 '16 at 14:57
  • Even if they don't we can always include them with `extern "C" { #include }` – dewaffled Feb 20 '16 at 14:57
  • @frymode - no, wrapping `#include` directives in `extern "C"` doesn't work. A source file that did `#include ` followed by `#include ` wouldn't get anything in `std` because of the include guards in math.h. – Pete Becker Feb 20 '16 at 15:07
  • It has always worked and afaik is the only way to disable mangling for C header - e.g. http://stackoverflow.com/a/23626709/4074081. – dewaffled Feb 20 '16 at 15:13
  • I mean the full code for proposed `cmath` would be `namespace __C_LANGUAGE_MATH { extern "C" { #include } }` – dewaffled Feb 20 '16 at 15:15