hides isnan in in C++14 / C++11?
我这里有一个小测试应用程序,它使用
1 2 3 4 5 6 7 8 9 10 11 12 | #include <iostream> #include <math.h> int main() { double d = NAN; std::cout << isnan(d) << ' '; return 0; } |
根据3种不同标准构建和运行:
1
2
3
4
5
6
7
8 $ 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
现在我们还包括
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include <iostream> #include <cmath> #include <math.h> int main() { double d = NAN; std::cout << std::isnan(d) << ' '; std::cout << isnan(d) << ' '; return 0; } |
构建并运行:
C ++ 98可以工作
1
2
3 $ g++ -std=c++98 main.cpp; ./a.out
1
1
C ++ 11和C ++ 14没有找到,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 $ 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) << '
';
^
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) << '
';
^
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)
^
请注意,包含的顺序并不重要。 如果我在
问题
-
为什么
isnan 消失了? - 无需返回并更改旧代码以在新标准下编译,有没有办法解决这个问题?
简要总结相关要点,主要来自Jonathan Wakely的优秀博客文章:
-
glibc <2.23的
math.h 声明过时的X / Openint isnan(double); 与C99 / C ++ 11版本(bool isnan(double); )不兼容。 -
glibc 2.23的
math.h 通过不在C ++ 11或更高版本中声明isnan 函数来解决这个问题。 -
所有这些仍然定义了一个
isnan 宏。#include 根据C ++标准的要求核对该宏。 -
GCC 6的libstdc ++提供了自己的特殊
math.h 头,它在全局命名空间中声明了一个bool isnan(double); (除非libcmath.h 声明了过时的签名),并且还按照标准的要求来核对宏。 -
在GCC 6之前,
#include 只包含libc中的标题,因此宏不会被破坏。 -
#include 总是核心宏。
净结果,在C ++ 11模式下:
1 2 3 4 | 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 |
如果从GCC查看
1 2 3 4 | . . . #include <math.h> . . . #undef isnan |
这就是订单无关紧要的原因 - 无论何时
由于
现在,标准对这种行为有什么看法?
[depr.c.headers]:
... every C header, each
of which has a name of the formname.h , behaves as if each name placed
in the standard library namespace by the corresponding cname header is
placed within the global namespace scope. It is unspecified whether
these names are first declared or defined within namespace scope
([basic.scope.namespace]) of the namespacestd and are then injected
into the global namespace scope by explicit using-declarations
([namespace.udecl]).[ Example: The header
assuredly provides its declarations
and definitions within the namespacestd . It may also provide these
names within the global namespace. The headerassuredly
provides the same declarations and definitions within the global
namespace, much as in the C Standard. It may also provide these names
within the namespacestd . — end example ]
所以
但是当它们都被包含在一个编译单元中时,它应该是一个灰色区域,尽管可以说上面的语句暗示两个版本必须互操作,在这种情况下它将是GCC / libstdc ++(某些版本)中的错误。
1 2 3 4 5 | ... #undef isinf #undef isnan #undef isnormal ... |
然后将所有那些未定义的宏实现为