【问题标题】:C++ gcc `floorf` not a member of `std`?C++ gcc`floorf`不是`std`的成员?
【发布时间】:2019-07-04 12:10:18
【问题描述】:

我有以下代码:

#include <cmath>

float foo(float x, unsigned int m, float q = 0.0f)
{
    return std::floorf(x * float(m) + q);
}

现在,当我尝试使用 g++ 5.4.0 和选项 -std=c++11 编译它时,我收到一条错误消息 ‘floorf’ is not a member of ‘std’

现在我的理解是 C++11 标准的第 26.8 条要求标准 C++ 库头 &lt;cmath&gt; 声明与标准 C 库头 &lt;math.h&gt; 相同的函数集,尽管在命名空间 @987654328 @;并且第 1.2 条规定将“C”解释为 C99;并且 C99 标准的第 7.12.9.2 条要求标准 C 库头文件 &lt;math.h&gt; 声明一个函数 float floorf(float)

因此,&lt;cmath&gt; 应该声明一个函数 float std::floorf(float),据我所知,它应该与我的代码匹配。

什么给了?我在这里遗漏了什么吗?

(我知道 C++11 也定义了 float std::floor(float);但是,我最近发现带有 f 后缀的浮点函数变体通常稍微快一些,所以我更愿意专门调用floorf()。)

【问题讨论】:

  • 这很奇怪,使用 clang++ 编译时似乎可以正常工作,但实际上使用 g++ 时,即使在最新版本上也无法正常工作。
  • 作为参考,我刚刚提交给Bugzilla
  • C++11 和 C++14 标准没有在表“标题 &lt;cmath&gt; 概要”中列出 floorf,它已在 C++17 中修复。对标准的迂腐解读可以得出结论,&lt;cmath&gt; 只需提供 ::floorf 而不是 std::floorf
  • 相关链接en.cppreference.com/w/cpp/numeric/math/floor。另外,“我最近发现浮点函数的 f 后缀变体通常稍微快一些”,这对我来说听起来很奇怪。
  • 对于速度差异,您是用-O0 测量的吗? std::pow 是一个调用powf 的函数,而powf 直接是powf,所以如果你不内联会更慢,但我希望内联可以很容易地消除差异。

标签: c++ c++11 gcc


【解决方案1】:

我相信您确实在标题中发现了一个错误。在我的 GCC 上,使用 GNU C 库 (glibc),我可以通过将 std:: 退出到全局命名空间中来解决问题,改变

    return std::floorf(x * float(m) + q);

    return ::floorf(x * float(m) + q);

解决方法有效,因为floorf() 属于 C 标准库,因此它在 glibc 中有一个全局符号。由于该变通方法使用 C++11 允许但不要求存在的全局符号,因此该变通方法是不可移植的。不过,对于 glibc,它似乎可以工作。

如果您愿意,可以通过将 #include &lt;cmath&gt; 更改为 #include &lt;math.h&gt; 并(据我所知)将所有 C-math-library 调用放到全局命名空间中,从而使解决方法变得可移植。不过,这仍然只是一种解决方法。

您可以继续将此作为错误报告:https://gcc.gnu.org/bugzilla/。此外,为了让 GCC 团队更加重视,您可以在此处链接错误报告,以表明已经有几双有能力的眼睛看到了这个问题。同时,干得好。

【讨论】:

  • “这不对,但它有效。” ——好吧,从某种意义上说,C++11 确实允许这样一个全局符号存在。但是它并没有强制要求,所以任何使用这个全局符号的程序都是不可移植的。
  • @ChristophLipka 如果您包含 &lt;math.h&gt;,它是可移植的。
  • @thb "in GCC's libc6" -- 没有这样的东西。我假设您的意思是 GNU C 库,但更正确地称为“glibc”而不是“libc6”并且不是 GCC 的一部分。 GCC 不提供 C 库,它使用系统现有的 C 库。
  • @JonathanWakely 在技术上是一个 C 头文件,包含在 C++ 中只是为了与 C 库兼容。我要避免依赖它,因为它会使事情变得笨拙。幸运的是,存在一种可移植的真正 C++ 方法,即使用 floor(float) 重载。
  • @ChristophLipka,从技术上讲,它是一个 C++ 标头,与同名的 C 标头具有相似(但不相同)的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
  • 1970-01-01
  • 2019-08-07
  • 1970-01-01
  • 2019-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多