c++ - std::abs(0u) 格式不正确吗?

标签 c++ c++11 language-lawyer cmath

给定以下程序:

#include <cmath>

int main()
{
    std::abs(0u) ;
}

gccclang 不同意这是否格式错误。将 gcclibstdc++ 一起使用,代码构建时不会出现错误或警告 ( see it live ),而将 clanglibc++ 它会产生以下错误( 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:

并包括以下项目:

  1. 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正在归档,其中包括:

  1. 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).

  1. 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/

相关文章:

c++ - 在拼贴游戏逻辑中使用 STL 算法

c++ - 如果底层容器发生变化,迭代器会发生什么变化?

c++ - 使用 shared_ptr : C++ 管理多个对象

c++ - 标准草案中提到的零长度数组是什么?

c++ - 下面的代码无法编译。可能是因为带有 std=c++2a 的 GCC 仍然没有完全跟上最新的草案

c++ - 双向链表模板中的几件事

c++ - 标准中的小(不重要)缺陷?

c++ - 标准布局和尾部填充

c++ - 获取组合框的文本 Win32 API C++ (NO MFC)

c++ - 将 2 个结构数组的信息输出到一个文件中