std :: abs(0u)是不是形成了?

时间:2015-04-20 14:39:55

标签: 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

1 个答案:

答案 0 :(得分:16)

看起来libstdc++是正确的,这不是格式错误,但我们会看到对于这是否是LWG活动问题2192中的缺陷存在一些疑问。

草案C ++ 11标准部分26.8 [c.math] 11说:

  

此外,还应有足够的额外过载来确保:

并包含以下项目:

  
      
  1. 否则,如果对应于double参数的任何参数具有double类型或整数类型,则所有参数都对应于   双参数有效地加倍。
  2.   

我们可以看到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,该报告会询问此实施是否正确,并且有一条回复说明:

  

[...]根据标准是好的,任何整数应该是   无条件地成为双倍。 [...]

错误报告最终导致LWG active issue 2192: Validity and return type of std::abs(0u) is unclear被提交,其中包括:

  
      
  1. 在C ++ 11中,额外的&#34;充分的过载&#34;规则从26.8 [c.math]   p11(另见LWG 2086)可以读取适用于std :: abs()   过载也可能导致以下情况发生   结论:
  2.         

    该计划

        #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)
        }
    
         

    需要格式良好,因为子弹2(&#34; [..]或者   26.8 [c.math] p11的整数类型[..]&#34;)(注意当前   LWG 2086的解决方案无法解决这个问题。)

         
        
    1. 由于返回类型的两个冲突要求,任何包含两者的翻译单元都可能格式不正确   重载std :: abs(int)。
    2.         

      在我看来,至少第二个结果并非意图,   我个人认为两者都是不幸的[...]它也应该是   注意到,相应的&#34;泛型类型函数&#34;规则集   7.25 p2 + 3中的C99 / C1x仅限于浮点函数   来自和,所以不能适用于绝对   功能(但对于fabs功能!)。

问题是这是否也适用于abs。这可能是一个缺陷,因为似乎没有办法解释当前的措辞以排除abs

因此,当前的措辞表明libstdc++符合要求,不清楚为什么libc++选择了当前的实现。我找不到错误报告,也没有涉及这个主题的讨论,LWG问题也没有提到不同的实现。

建议的解决方案会使std::abs(0u)格式不正确:

  

如果使用无符号整数类型的参数调用abs()   无法通过整数提升([conv.prom])转换为int   程序是不正确的。 [注意:可以提升为int的参数   允许与C兼容。 - 尾注]

虽然有些人可能质疑使用abs与无符号类型的概念,但Howard Hinnant在报告中指出,在使用模板时,这些后果可能并不明显,并提供了一个例子:

  

[...]特别是在C ++中,我们有模板和涉及的类型   在设计时对程序员来说并不总是很明显。例如,   考虑:

template <class Int>
Int
analyze(Int x, Int y)
{
  // ...
  if (std::abs(x - y) < threshold)
  {
    // ...
  }
  // ...
}