是std :: abs(0u)不成形吗? [英] Is std::abs(0u) ill-formed?

查看:250
本文介绍了是std :: abs(0u)不成形吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下程序:

  #include< cmath> 

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

gcc code> clang 不同意这是否是不成形的。使用 gcc libstdc ++ 代码构建没有错误或警告( clang 与 libc ++ 使用 cang cang cull / melang.org/wandbox/permlink/5sASqwTFEidudt0S code>它会生成以下错误( 查看实时 ):

 错误:调用'abs'不明确
std :: abs(0u);
^ ~~~~~~~

哪个结果正确? abs(0u)是否含糊不清?






MSalters指出了一个有趣的相关问题: std :: abs 的模板版本。

解决方案

看起来像 libstdc ++ 是正确的,这不是错误的,虽然我们会看到有一些怀疑这是否是LWG活动问题 2192 中的缺陷。



草稿C ++ 11标准版块 26.8 [c.math] 11 说:


此外,还有额外的重载,足以确保: / p>

并包含以下项目:



  1. 否则,如果对应于double参数的任何参数具有double类型或整数类型,那么对应于
    double参数的所有参数都有效地转换为double。


,我们可以看到 libstdc ++ href =https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/c_std/cmath#L92 =nofollow>确实提供此 case:

 模板< 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)resort to std :: abs(double)if llabs不存在,这问题如果这个实现是正确的,一个响应说:


[...]标准,任何整数应该是
无条件变为双。 [...]


错误报告最终会导致 LWG活动问题2192:std :: abs(0u)的有效性和返回类型不清楚其中包括:



  1. 在C ++ 11中,额外的足够过载规则来自26.8 [ math]
    p11(参见LWG 2086)可以被读取以适用于std :: abs()
    重载,这可以导致以下可能的
    结论: li>

程序

  #include< ; type_traits> 
#include< cmath>

static_assert(std :: is_same< decltype(std :: abs(0u)),double>(),Oops);

int main(){
std :: abs(0u); //调用std :: abs(double)
}

因为26.8 [c.math] p11的子项2([..]或
整数类型[..])注意,LWG 2086的当前
分辨率


  1. 任何翻译单元,包括两者,可能由于两个冲突的要求对于返回类型
    的重载std :: abs(int)。

在我看来,至少第二个结果是不打算的,
个人我认为两个都是不幸的[...]它也应该是
注意,相应的通用类型函数规则设置从
C99 / C1x在7.25 p2 + 3被限制为浮点函数
from,因此不能应用于abs
函数(但是对于fabs函数!)。


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



因此,当前的措辞表示 libstdc ++ 是符合的,不清楚为什么 libc ++ 选择了它们的当前实现。我可以找到没有错误报告或讨论涉及此主题和LWG问题没有提到不同的实施。



建议的解决方案将使 std :: abs(0u)形式:


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


可能怀疑使用无符号类型使用 abs 的概念Howard Hinnant在报告中指出,当使用模板时,这样的后果可能不明显,并提供了一个例子:

特别是在C ++中,我们有模板,涉及的类型
在设计时并不总是对程序员显而易见。例如,
考虑:

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



Given the following program:

#include <cmath>

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

gcc and clang disagree on whether this is ill-formed. Using gcc with libstdc++ the code builds without error or warning (see it live), while using clang with libc++ it generates the following error (see it live):

error: call to 'abs' is ambiguous
std::abs(0u) ;
^~~~~~~~

Which result is correct? Should abs(0u) be ambiguous or not?


MSalters points out an interesting related question: Template version of std::abs.

解决方案

Looks like libstdc++ is correct, this is not ill-formed, although we will see there are some doubts expressed over whether this is a defect in LWG active issue 2192.

The draft C++11 standard section 26.8 [c.math] paragraph 11 says:

Moreover, there shall be additional overloads sufficient to ensure:

and includes the following item:

  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.

and we can see this libstdc++ does indeed provide for this case:

template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
                                                  double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }

There is a also a gcc bug report std::abs (long long) resorts to std::abs (double) if llabs is absent, which questions if this implementation is correct and one response says:

[...]is fine per the Standard, any integer is supposed to unconditionally become double. [...]

The bug report eventually lead to LWG active issue 2192: Validity and return type of std::abs(0u) is unclear being filed which says amongst other things:

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

The question is whether this was intended to apply to abs as well. This could be a defect since there does not seem to a way to interpret the current wording to exclude abs.

So current wording indicates libstdc++ is conformant, it is not clear why libc++ has chosen their current implementation as it is. I can find no bug reports nor discussions involving this topic and the LWG issue does not mention diverging implementations.

The proposed solution would make std::abs(0u) ill-formed:

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]

While some may question the notion of using abs with an unsigned type Howard Hinnant points out in the report that when using templates such consequences may not be apparent and provides an example:

[...]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)
  {
    // ...
  }
  // ...
}

这篇关于是std :: abs(0u)不成形吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆