对腹肌的模棱两可的呼唤
Ambiguous call to abs
>我有一个自定义数据类型,实际上可以是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
段说:
此外,还应有额外的超载,足以确保:
并包括以下项目:
否则,如果对应于双精度参数
- 的任何参数具有双精度类型或整数类型,则对应于 双精度参数有效地转换为双精度。
由于 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
。
- "Inverse SFINAE"避免模棱两可的过载
- 操作员C++的模棱两可的过载
- 模棱两可的重载模板
- 调用重载的"<大括号括起来的初始值设定项列表>"对于对来说就足够了是模棱两可的
- 模棱两可的 != reverse_iterator运算符
- SFINAE不能防止模棱两可的操作员过载吗?
- VSCode 说 std::chrono 是模棱两可的,如果运算符<<重载
- 为什么对模板的调用不模棱两可?
- 修复重载运算符的使用'+'模棱两可?
- 为什么同时覆盖全局新运算符和特定于类的运算符不是模棱两可的行为?
- Antlr4 C++访问模棱两可的分支
- 模棱两可的调用 - 模板化函数
- 在SESHAT中,对"元组"的引用是模棱两可的
- C++17 年与 Clang 的模棱两可的部分专业化
- gcc 中的模棱两可的运算符
- 将 NULL 转换为长不是模棱两可吗?
- C++ lambda 模棱两可的调用
- 带有模板的循环缓冲区在Keil MDK5上是模棱两可的错误?
- 对腹肌的模棱两可的呼唤
- 对'abs'的呼唤在目标C++中是模棱两可的