我在Fedora 26系统上使用GCC 5.4.0和Boost 1.67.0(这不是系统的默认编译器)。如果我编译以下a.cpp
:
#include <boost/any.hpp>
使用命令行:
g++ a.cpp -c -o a.o --std=c++11 -D__CORRECT_ISO_CPP11_MATH_H_PROTO -I/path/to/boost/include
我收到以下错误:
... blah blah blah ...
/path/to/boost/include/boost/container_hash/detail/hash_float.hpp:212:36: error: no matching function for call to ‘fpclassify(float&)’
switch (std::fpclassify(v))
... blah blah blah ...
如果我没有定义_CORRECT_ISO_CPP11_MATH_H_PROTO
编译结束且没有错误。
以前的Boost版本不会发生这种情况。例如1.62.0。为什么现在发生?
注意:在某些GCC 6.x版本中会出现这种情况:GCC 6.1(Godbolt)和6.2,但6.3和更高版本没有。谢谢@Justin。此外,clang v3.5及更高版本(未经过广泛测试)也不会发生这种情况。
答案 0 :(得分:3)
问题可以通过以下方式重现:
#define __CORRECT_ISO_CPP11_MATH_H_PROTO 1
#include <cmath>
int main()
{
float v;
std::fpclassify(v);
}
C ++ 11标准(N3337)为3个浮点类型指定了std::fpclassify
的3个重载(没有constexpr
)。
代码无法编译,因为cmath
标题in these versions of gcc包含(伪代码):
#include <math.h>
#undef fpclassify
#if __cplusplus >= 201103L
#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO
constexpr int fpclassify(float __x) {.....}
constexpr int fpclassify(double __x) {.....}
constexpr int fpclassify(long double __x) {.....}
#endif
template<typename _Tp>
constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, int>::__type
fpclassify(_Tp __x)
{
这意味着std::fpclassify
只能通过整数参数找到。 (我相信这个整数重载是为了满足浮点函数的整数参数应该调用double
重载的一般数学要求。)
我找到了the relevant commit to libstdc++。评论建议只有在math.h
已经为三个浮点类型提供了fpclassify
的三个重载时才应定义此宏。
libstdc ++的autoconf代码检查现有系统math.h
并发出此宏,如果它已经定义了fpclassify
的三个重载。
如果您处于math.h
未提供重载的实现中,则不应使用此宏,否则您将使实现不符合。
答案 1 :(得分:3)
定义__CORRECT_ISO_CPP11_MATH_H_PROTO
意味着&#34;此libstdc ++配置和构建的libc具有提供C ++ 11函数的math.h
,因此<cmath>
不应该&#39;试着提供自己的&#34;。
为什么你自己定义那个宏呢?