Why isnan is ambiguous and how to avoid it?

Since it isnancan be either a macro (in C ++ 98) or a function defined in the namespace std(in C ++ 11), an obvious (and possibly naive) way to write code that works in both cases is illustrated by this simple example

#include <cmath>

int main() {
  double x = 0;
  using namespace std;
  isnan(x);
}

However, compilation gives errors both in GCC (with -std = C ++ 11) and Clang:

test.cc: In function ‘int main()’:
test.cc:6:10: error: call of overloaded ‘isnan(double&)’ is ambiguous
   isnan(x);
          ^
test.cc:6:10: note: candidates are:
In file included from /usr/include/features.h:374:0,
                 from /usr/include/x86_64-linux-gnu/c++/4.8/bits/os_defines.h:39,
                 from /usr/include/x86_64-linux-gnu/c++/4.8/bits/c++config.h:426,
                 from /usr/include/c++/4.8/cmath:41,
                 from test.cc:1:
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:234:1: note: int isnan(double)
 __MATHDECL_1 (int,isnan,, (_Mdouble_ __value)) __attribute__ ((__const__));
 ^
In file included from test.cc:1:0:
/usr/include/c++/4.8/cmath:626:3: note: constexpr bool std::isnan(long double)
   isnan(long double __x)
   ^
/usr/include/c++/4.8/cmath:622:3: note: constexpr bool std::isnan(double)
   isnan(double __x)
   ^
/usr/include/c++/4.8/cmath:618:3: note: constexpr bool std::isnan(float)
   isnan(float __x)
   ^

Why is this ambiguous in C ++ 11 and how to make it work with both C ++ 98 and C ++ 11, preferably without too much conditional compilation?

+4
source share
4 answers

libstdc++, STD- C ++ 0x ( std ) , OP:

#include <stdlib.h>
#include <cmath>
#include <stdio.h>

using namespace std;

int main(int argc, char** argv)
{
    double number = 0;
    if (isnan(number))
    {
        printf("Nan\n");
    }
    return 0;
}

:

, , libstd++ , ++ 03 - ++ 0x ( , , )

, , , :

isnan , :: isnan, std:: isnan

::isnan, , pre ++ 11 ++ 11.

, libstdc++, libc++, , , , , #if/#else.

, MM isnan, constexpr, , , .

. : [++ 11] 'isnan bool. libstdc++.

gcc/clang, , __builtin_isnan, . gcc docs on builtins . . glibc isnan . .

+6

, , ++ 11 . C isnan C99, ++ 98 ++ 03 C89. , ++ 98/03 C99, isnan (, , ), .

unsing using, , ++ 11 ( libstd++) . ( , isnan namespace.)

template <typename T>
bool
my_isnan(const T x)
{
#if __cplusplus >= 201103L
  using std::isnan;
#endif
  return isnan(x);
}

, -, #if.

+3

:

bool isNaN(double x) { 
  return x != x;
}
+2

, isnan , - std. " std;" .

, .

// drop 'using namespace std;'

#ifndef isnan
using std::isnan;
#endif

[EDIT] isnan std:: isnan. : isnan, , .

// drop 'using namespace std;'

#ifndef isnan
#define isnan(x) std::isnan(x)
#endif

[EDIT # 2] " ++ 98, ( ) isnan (double &) std"... - .

#ifndef isnan
#if __cplusplus <= 199711L  // c++98 or older
#  define isnan(x) ::isnan(x)
#else
#  define isnan(x) std::isnan(x)
#endif
#endif

In the real world, however, compilers have different rules for __cplusplus, which are completely incompatible. For a more general discussion and answers, I will postpone how to make the portable function isnan / isinf .

+1
source

Source: https://habr.com/ru/post/1616297/


All Articles