对 abs 的模糊调用
Ambiguous call to abs
我有一个自定义数据类型,实际上可以是 float
或 double
。在除 OSX 之外的每个 OS 上,我都能够成功构建此 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 和 [=32= 上会出现相同的错误].
晶圆厂 Visual Studio 出错:
349 error C2668: 'fabs' : ambiguous call to overloaded function
更新
此示例在我们的 OS X 系统上编译,尽管在 几乎 相同的项目中它没有。解决方案是在源代码中明确包含 <cstdlib>
,而不是在另一个 header 中返回。原因尚不清楚,但似乎是 xcode/clang 没有正确遵循我们的 header 包含。
问题是 libc++
不完全符合 std::abs in cmath 的积分重载的 C++11:
double fabs( Integral arg ); (7) (since C++11)
包含 cstdlib 可以解决您的问题,因为 header 具有专门针对整数类型的重载。
参考草案 C++11 标准部分 26.8
[c.math] 段落 11
说:
Moreover, there shall be additional overloads sufficient to ensure:
并包括以下项目:
- 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.
这种情况很可能会因 LWG active issue 2192: Validity and return type of std::abs(0u) is unclear 而改变。我猜 libc++
选择不在 cmath
中提供重载是由于此缺陷报告中提出的问题。
有关详细信息,请参阅 Is std::abs(0u) ill-formed?。
解决方案是在 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
。)
我有一个自定义数据类型,实际上可以是 float
或 double
。在除 OSX 之外的每个 OS 上,我都能够成功构建此 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 和 [=32= 上会出现相同的错误].
晶圆厂 Visual Studio 出错:
349 error C2668: 'fabs' : ambiguous call to overloaded function
更新
此示例在我们的 OS X 系统上编译,尽管在 几乎 相同的项目中它没有。解决方案是在源代码中明确包含 <cstdlib>
,而不是在另一个 header 中返回。原因尚不清楚,但似乎是 xcode/clang 没有正确遵循我们的 header 包含。
问题是 libc++
不完全符合 std::abs in cmath 的积分重载的 C++11:
double fabs( Integral arg ); (7) (since C++11)
包含 cstdlib 可以解决您的问题,因为 header 具有专门针对整数类型的重载。
参考草案 C++11 标准部分 26.8
[c.math] 段落 11
说:
Moreover, there shall be additional overloads sufficient to ensure:
并包括以下项目:
- 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.
这种情况很可能会因 LWG active issue 2192: Validity and return type of std::abs(0u) is unclear 而改变。我猜 libc++
选择不在 cmath
中提供重载是由于此缺陷报告中提出的问题。
有关详细信息,请参阅 Is std::abs(0u) ill-formed?。
解决方案是在 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
。)