我注意到 appleclang++ (v14.0.0) 在将浮点输入传递给时似乎返回单精度浮点cmath
's sqrt
。当切换到 gcc/clang 时,我很惊讶地得到了不同的结果。
这是我的最小可重现示例:
#include <cmath>
#include <cstdio>
#include <type_traits>
int main()
{
float f = 1+1e-7;
auto X = sqrt(f);
printf("%16s says X is a %6s with value: %0.17g\n",
#ifdef __clang__
#if defined(__apple_build_version__)
"appleclang++",
#else
"clang++",
#endif
#elif __GNUC__
"g++",
#else
"unknown compiler",
#endif
std::is_same<float, decltype(X)>::value ? "float" : "double",
X);
}
对于不同的编译器我看到:
appleclang++ says X is a float with value: 1
clang++ says X is a double with value: 1.000000059604643
g++ says X is a double with value: 1.000000059604643
我正在编译-std=c++11
just 为了确定 https://cplusplus.com/reference/cmath/sqrt/.
如果我切换到std::sqrt
然后每个人都同意这是一个浮动,但我仍然很好奇。这种行为是否是sqrt
确实由编译器决定还是 appleclang 是非标准的?
一般来说,对于大多数数学函数,C++ 标准库对每种浮点类型都有一个重载,该重载采用该类型作为参数并返回相同的类型。此外,还有重载,因此整数参数的行为就像转换为double
在通过之前。
然而,这里的问题是你使用sqrt
来自全局命名空间范围,这是错误的。它应该是std::sqrt
.
当包括<cmath>
你只能保证所有的重载std::sqrt
中提供了std::
命名空间范围。您需要包括<math.h>
以保证所有重载在全局命名空间范围内可用,并且您需要同时包含两者以确保所有重载在全局和全局命名空间中都可用std::
命名空间范围。顺便说一句,这会影响从 C 派生的所有标准库头。
不过,我建议不要(单独)使用<math.h>
头,因为它缺少一些其他特定于 C++ 的数学函数,还因为它自 C++98 以来已被弃用,直到包含 C++20,然后才针对 C++23 弃用。同理其他<_.h>
标准库头文件也已被弃用,并且缺少相应部分中包含的某些部分<c_>
标头。不幸的是,即使只包含全局名称空间污染,也无法避免<c_>
标头。
当包含不匹配时,未指定哪些重载(如果有)将可见,然后有可能不获取float sqrt(float)
超载你只能得到double sqrt(double)
过载,或与此相关的任何其他过载,例如一个期望int
并返回一个double
,这会导致非常奇怪的结果。
(虽然最后一个例子有点牵强,因为没有好的实现原因会导致这种行为。实现原因double
重载的特殊之处在于它是由底层 C 标准库实现(通常是系统的一部分)提供的,而不是通常在其之上单独构建的 C++ 标准库实现。)
也有可能看不到重载并且程序无法编译。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)