给定以下程序:
#include <cmath>
int main()
{
std::abs(0u) ;
}
gcc
和 clang
不同意这是否格式错误。将 gcc
与 libstdc++
一起使用,代码构建时不会出现错误或警告 ( see it live ),而将 clang
与 libc++
它会产生以下错误( see it live ):
error: call to 'abs' is ambiguous
std::abs(0u) ;
^~~~~~~~
哪个结果是正确的? abs(0u)
是否应该模棱两可?
MSalters 指出了一个有趣的相关问题:Template version of std::abs .
最佳答案
看起来 libstdc++
是正确的,这不是格式错误,尽管我们会看到有人怀疑这是否是 LWG 事件问题 2192
中的缺陷.
C++11 标准草案草案 26.8
[c.math] 段落 11
说:
Moreover, there shall be additional overloads sufficient to ensure:
并包括以下项目:
- Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to double parameters are effectively cast to double.
我们可以看到这个 libstdc++
确实 indeed provide for this案例:
template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }
还有一个 gcc
错误报告 std::abs (long long) resorts to std::abs (double) if llabs is absent , 哪个问题这个实现是否正确,一个回答说:
[...]is fine per the Standard, any integer is supposed to unconditionally become double. [...]
错误报告最终导致 LWG active issue 2192: Validity and return type of std::abs(0u) is unclear正在归档,其中包括:
- In C++11 the additional "sufficient overload" rule from 26.8 [c.math] p11 (see also LWG 2086) can be read to be applicable to the std::abs() overloads as well, which can lead to the following possible conclusions:
The program
#include <type_traits> #include <cmath> static_assert(std::is_same<decltype(std::abs(0u)), double>(), "Oops"); int main() { std::abs(0u); // Calls std::abs(double) }
is required to be well-formed, because of sub-bullet 2 ("[..] or an integer type [..]") of 26.8 [c.math] p11 (Note that the current resolution of LWG 2086 doesn't fix this problem).
- Any translation unit including both and might be ill-formed because of two conflicting requirements for the return type of the overload std::abs(int).
It seems to me that at least the second outcome is not intended, personally I think that both are unfortunate [...] It should also be noted, that the corresponding "generic type function" rule set from C99/C1x in 7.25 p2+3 is restricted to the floating-point functions from and , so cannot be applied to the abs functions (but to the fabs functions!).
问题是这是否也适用于 abs
。这可能是一个缺陷,因为似乎没有办法解释当前的措辞以排除 abs
。
所以当前的措辞表明 libstdc++
是一致的,不清楚为什么 libc++
选择了它们当前的实现。我找不到涉及该主题的错误报告或讨论,LWG 问题也没有提及不同的实现。
建议的解决方案会使 std::abs(0u)
格式错误:
If abs() is called with an argument of unsigned integral type that cannot be converted to int by integral promotion ([conv.prom]), the program is ill-formed. [Note: arguments that can be promoted to int are permitted for compatibility with C. — end note]
虽然有些人可能会质疑将 abs
与无符号类型一起使用的概念,但 Howard Hinnant 在报告中指出,使用模板时,此类后果可能并不明显,并提供了一个示例:
[...]especially in C++ where we have templates, and the types involved are not always apparent to the programmer at design time. For example, consider:
template <class Int> Int analyze(Int x, Int y) { // ... if (std::abs(x - y) < threshold) { // ... } // ... }
关于c++ - std::abs(0u) 格式不正确吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29750946/