对腹肌的模棱两可的呼唤

Ambiguous call to abs

本文关键字:模棱两可 呼唤      更新时间:2023-10-16

>我有一个自定义数据类型,实际上可以是float也可以是double。在除OSX以外的每个操作系统上,我都能够成功构建此C++11模板:

#include <cmath>
#include <cstdlib>
#include <cstdint>
template< class REAL_T >
inline REAL_T inhouse_abs(REAL_T i_val)
{
return std::abs((REAL_T)i_val);
}
int main()
{
int32_t ui = 2;
inhouse_abs(ui);
return 0;
}

但是,clang 6.0 (3.5 LLVM) 报告了一个不明确的函数调用。如果我将abs更改为fabs,则错误在OSX上得到解决,但是现在在我的Linux clang,gcc和Visual Studio上出现了相同的错误。

使用晶圆厂的Visual Studio上的错误:

349 error C2668: 'fabs' : ambiguous call to overloaded function

更新

这个例子在我们的OS X系统上编译,尽管在几乎相同的项目中它没有。解决方案是在源中显式包含<cstdlib>,而不是返回另一个标头。原因尚不清楚,但似乎是 xcode/clang 没有正确遵循我们的标头包含。

问题是libc++并不完全符合 C++11 与 cmath 中 std::abs 的积分重载:

double      fabs( Integral arg ); (7)   (since C++11)

包含 cstdlib 可以解决您的问题,因为该标头具有专门针对整数类型的重载。

作为参考,C++11标准草案第26.8[c.math]11段说:

此外,还应有额外的超载,足以确保:

并包括以下项目:

    否则,如果对应于双精度参数
  1. 的任何参数具有双精度类型或整数类型,则对应于 双精度参数有效地转换为双精度。

由于 LWG 活动问题 2192:std::abs(0u) 的有效性和返回类型不清楚,这种情况很可能会改变。我猜libc++由于此缺陷报告中提出的问题,选择不提供cmath的重载。

请参阅 std::abs(0u) 格式不正确吗?以获取更多详细信息。

解决方案是在OS X机器上显式#include <cstdlib>,因为出于某种原因,Visual Studio在我们的依赖项中找到它并包含它,但clang没有。我将尝试重现我们项目具有的类似包含链,并以极简主义的方式重现错误,因为它可能仍然是 Xcode 或 Visual Studio 的问题。

如果有许多模板函数导致此问题,则可以使用以下插入式替换:

#include <cmath>
#include <cstdlib>
#include <type_traits>
namespace util {

template <class T>
auto abs(T value) -> std::enable_if_t<std::is_unsigned<T>::value,
T> { return value; }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_floating_point<T>::value,
T> { return std::fabs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_same<T, int>::value,
T> { return std::abs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_same<T, long>::value,
T> { return std::labs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_same<T, long long>::value,
T> { return std::llabs(value); }
template <class T>
auto abs(T value) -> std::enable_if_t<std::is_signed<T>::value &&
!std::is_floating_point<T>::value &&
!std::is_same<T, int>::value &&
!std::is_same<T, long>::value &&
!std::is_same<T, long long>::value,
T> { return std::abs(value); }

} // namespace util

只需将std::abs呼叫替换为util::abs即可。(需要c++11