-3

我在 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 和更高版本。谢谢@贾斯汀。此外,clang v3.5 及更高版本(未经广泛测试)不会发生这种情况。

4

2 回答 2

3

该问题可以通过以下方式重现:

#define __CORRECT_ISO_CPP11_MATH_H_PROTO 1
#include <cmath>

int main()
{ 
    float v;
    std::fpclassify(v);
}

std::fpclassifyC++11 标准 (N3337)为 3 种浮点类型(不带)指定了 3 种重载constexpr

代码无法编译,因为这些版本的 gcccmath中的标头包含(伪代码):

#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重载的一般数学要求)。


我找到了对 libstdc++ 的相关提交。注释建议只有在已经为三种浮点类型math.h提供了三个重载的情况下才应该定义这个宏。fpclassify

libstdc++ 的 autoconf 代码检查现有系统math.h,如果它已经定义了fpclassify.

如果你在一个math.h不提供重载的实现上,那么你不应该使用这个宏,否则你会渲染你的实现不合格。

于 2018-05-31T23:06:56.037 回答
3

定义__CORRECT_ISO_CPP11_MATH_H_PROTO的意思是“这个 libstdc++ 配置和构建的 libc 有一个math.h提供 C++11 功能的 libc,所以<cmath>不应该尝试提供它自己的”。

你到底为什么要自己定义那个宏?

于 2018-05-31T23:22:26.220 回答