我有自定义数据类型,实际上可以是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上会出现相同的错误。
使用fabs的Visual Studio出错:
349 error C2668: 'fabs' : ambiguous call to overloaded function
更新
此示例在我们的OS X系统上编译,但在几乎相同的项目中却没有。解决方案是在源代码中明确包含<cstdlib>
,而不是在另一个头中。原因尚不清楚,但似乎是xcode / clang没有按照我们的标题正确包含。</ p>
答案 0 :(得分:10)
问题是libc++
并不完全符合C ++ 11与std::abs in cmath的整数重载:
double fabs( Integral arg ); (7) (since C++11)
包含cstdlib解决了您的问题,因为该标头具有专门针对整数类型的重载。
供参考,草案C ++ 11标准部分26.8
[c.math] 段11
说:
此外,还应有足够的额外过载来确保:
并包含以下项目:
- 否则,如果对应于double参数的任何参数具有double类型或整数类型,则所有参数都对应于 双参数有效地加倍。
醇>
由于LWG active issue 2192: Validity and return type of std::abs(0u) is unclear,这种情况很可能会发生变化。由于此缺陷报告中出现的问题,我猜libc++
选择不在cmath
中提供重载。
有关详细信息,请参阅Is std::abs(0u) ill-formed?。
答案 1 :(得分:3)
解决方案是在OS X机器上显式#include <cstdlib>
,因为某些原因Visual Studio在我们的依赖项中找到它并包含它,但clang没有。我将尝试重现我们的项目具有的类似的包含链,并以极简主义的方式重现错误,因为它可能仍然是Xcode或Visual Studio的问题。
答案 2 :(得分:0)
如果您有许多导致此问题的模板功能,则可以使用以下嵌入式替换:
#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
。)