对abs

时间:2015-05-06 18:16:43

标签: c++ macos c++11 cmath

我有自定义数据类型,实际上可以是floatdouble。在除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>

3 个答案:

答案 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说:

  

此外,还应有足够的额外过载来确保:

并包含以下项目:

  
      
  1. 否则,如果对应于double参数的任何参数具有double类型或整数类型,则所有参数都对应于   双参数有效地加倍。
  2.   

由于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。)