I have here a small test app which uses isnan
from <math.h>
:
#include <iostream>
#include <math.h>
int main()
{
double d = NAN;
std::cout << isnan(d) << '\n';
return 0;
}
Build and run under 3 different standards:
$ g++ -std=c++98 main.cpp; ./a.out 1 $ g++ -std=c++11 main.cpp; ./a.out 1 $ g++ -std=c++14 main.cpp; ./a.out 1
Now we also include <cmath>
, and test with both isnan
and std::isnan
:
#include <iostream>
#include <cmath>
#include <math.h>
int main()
{
double d = NAN;
std::cout << std::isnan(d) << '\n';
std::cout << isnan(d) << '\n';
return 0;
}
Build and run:
C++98 works
$ g++ -std=c++98 main.cpp; ./a.out 1 1
C++11 and C++14 don't, isnan
is not found.
$ g++ -std=c++11 main.cpp main.cpp: In function ‘int main()’: main.cpp:10:25: error: ‘isnan’ was not declared in this scope std::cout << isnan(d) << '\n'; ^ main.cpp:10:25: note: suggested alternative: In file included from main.cpp:3:0: /usr/include/c++/5/cmath:641:5: note: ‘std::isnan’ isnan(_Tp __x) ^ $ g++ -std=c++14 main.cpp main.cpp: In function ‘int main()’: main.cpp:10:25: error: ‘isnan’ was not declared in this scope std::cout << isnan(d) << '\n'; ^ main.cpp:10:25: note: suggested alternative: In file included from main.cpp:3:0: /usr/include/c++/5/cmath:641:5: note: ‘std::isnan’ isnan(_Tp __x) ^
Note the order of inclusion is not important. If I include <cmath>
before <math.h>
or after, the result is the same.
Questions
isnan
gone?Briefly summarizing the pertinent points, mostly from Jonathan Wakely's excellent blog post:
math.h
declares the obsolete X/Open int isnan(double);
that is incompatible with the C99/C++11 version (bool isnan(double);
).math.h
fixes this by not declaring the isnan
function in C++11 or later.isnan
macro. #include <cmath>
nukes that macro as required by the C++ standard.math.h
header that declares a bool isnan(double);
in the global namespace (unless the libc math.h
declares the obsolete signature) and also nukes the macros as required by the standard.#include <math.h>
simply included the header from your libc, so the macro isn't nuked.#include <cmath>
always nukes the macros.Net result, in C++11 mode:
glibc < 2.23, GCC < 6: <math.h> uses the macro; <cmath> uses obsolete signature
glibc >= 2.23, GCC < 6: <math.h> uses the macro; <cmath> results in error
glibc < 2.23, GCC >= 6: <math.h> and <cmath> use obsolete signature
glibc >= 2.23, GCC >= 6: <math.h> and <cmath> use standard signature