0

My understanding is that the function std::isnan is only available from C++11 onwards. Further, g++ uses -std=gnu++98 unless specifically told not to.

So why does this compile?

>> cat test.cpp
#include <cmath>
int main(int argc, char** argv)
{
    return std::isnan(0);
}

>> g++ test.cpp

Is there a flag to take the function out of <cmath>?

  • 3
    Could be an extension since [it exists in C99](http://en.cppreference.com/w/c/numeric/math/isnan). What happens if you compile with `-pedantic`? – NathanOliver Jun 09 '17 at 18:42
  • @NathanOliver It still compiles with `-pedantic`. Shouldn't it be in the global namespace if it were using the C99 macro? –  Jun 09 '17 at 18:45
  • Those C macros are actually implemented as function per the C++ standard ([see this answer](https://stackoverflow.com/a/44370539/4342498)). What is interesting is even in gcc 4.4.7 with -std=c++98 you see `__gnu_cxx::__enable_if::__value, int>::__type std::isnan(int)` in the assembly. – NathanOliver Jun 09 '17 at 18:54

2 Answers2

5

Compiler developers are lazy about exactly removing every feature that should only be available in the next version of the standard, especially when related libraries (C99) have it at the same time.

The utility (of validing your code actually obeys a specific standard) is not high enough for compiler writers to work extremely hard at making their compiler provide that service.

Instead, what usually happens is new features are implemented under specific standard flags. Sometimes they are accidentally backported. When the standard finalizes, the partial implementation exists for a while until it gets good enough.

Then work starts on the next version of the standard. The next version flag gives you a less stable development environment, as new features are tried out and discarded and changed.

Some effort it put into not backporting stuff, but it isn't a showstopper.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • This is basically it. No matter what compiler you use, if you expect it to strictly comply to a specific language standard, you're going to be disappointed. – Lightness Races in Orbit Jun 09 '17 at 18:57
  • those functions precede their addition to standard. Their existence in various forms foretold the standard. VC2010 and gcc 4.6 had those. But other compilers or different platforms had it named differently, e.g. on Solaris it wasn't part of std namespace until C++11, later it is just reimported into namespace, so both standard and non-standard symbol exist. Standard doesn't deny backward compatibility or extensions – Swift - Friday Pie Jun 09 '17 at 20:58
  • @Swift As it was foretold, `std::isnan` will be. – Yakk - Adam Nevraumont Jun 09 '17 at 21:28
2

This is a long-standing issue, documented in the FAQ but in a way that you wouldn't necessarily be able to make sense of.

4.3. _XOPEN_SOURCE and _GNU_SOURCE are always defined?

On Solaris, g++ (but not gcc) always defines the preprocessor macro _XOPEN_SOURCE. On GNU/Linux, the same happens with _GNU_SOURCE. (This is not an exhaustive list; other macros and other platforms are also affected.)

These macros are typically used in C library headers, guarding new versions of functions from their older versions. The C++98 standard library includes the C standard library, but it requires the C90 version, which for backwards-compatibility reasons is often not the default for many vendors.

More to the point, the C++ standard requires behavior which is only available on certain platforms after certain symbols are defined. Usually the issue involves I/O-related typedefs. In order to ensure correctness, the compiler simply predefines those symbols.

Note that it's not enough to #define them only when the library is being built (during installation). Since we don't have an 'export' keyword, much of the library exists as headers, which means that the symbols must also be defined as your programs are parsed and compiled.

To see which symbols are defined, look for CPLUSPLUS_CPP_SPEC in the gcc config headers for your target (and try changing them to see what happens when building complicated code). You can also run g++ -E -dM - < /dev/null" [sic] to display a list of predefined macros for any particular installation.

This has been discussed on the mailing lists quite a bit.

This method is something of a wart. We'd like to find a cleaner solution, but nobody yet has contributed the time.

To explain:

glibc is what provides the standard C library. It supports several modes.

It supports various strict C modes and strict POSIX modes. In these modes, when only standard headers are included, only standard functions are available. In C90 mode, this does not include isnan.

It supports various extension modes. In these modes, non-standard functions are also available. In C90 + extensions mode, this includes isnan. The _GNU_SOURCE preprocessor macro is the one that enables all extensions.

libstdc++ is what provides the standard C++ library. It requires more from glibc than what strict C90 mode offers. Therefore, there are only two options: either libstdc++ does not offer those standard C++ features it cannot provide, or libstdc++ forcibly enables glibc's extensions even in strict ANSI mode. Both mean a failure to conform to the C++ standard, but the former restricts features, while the latter provides them. The latter is seen as the lesser evil.

The only reasonable way to fix this is for glibc to provide some non-standard way to access its extensions even in strict ANSI mode. No such way exists yet, and until such a way is created, non-standard names will be available even in meant-to-be-standard C++ compilation modes.

Community
  • 1
  • 1