Ambiguous call to abs

后端 未结 3 1035
执念已碎
执念已碎 2021-01-11 18:15

I have a custom data type that in practice can be either float or double. On every OS except OSX, I am able to successfully build this C++11 templa

相关标签:
3条回答
  • 2021-01-11 18:21

    The solution was to explicitly #include <cstdlib> on the OS X machine, as for some reason Visual Studio finds it in our dependencies and includes it, but clang does not. I will try to reproduce a similar chain of includes that our project has and reproduce the error in a minimalist way, as it may still be a problem either with Xcode or Visual Studio.

    0 讨论(0)
  • 2021-01-11 18:23

    The issue is that libc++ is not entirely C++11 compliant with the integral overload for std::abs in cmath:

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

    Including cstdlib solves your problem since that header has overloads specifically for integer types.

    For reference the draft C++11 standard section 26.8 [c.math] paragraph 11 says:

    Moreover, there shall be additional overloads sufficient to ensure:

    and includes the following item:

    1. 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.

    This is situation very likely to change due to LWG active issue 2192: Validity and return type of std::abs(0u) is unclear. I am guessing libc++ choose not to provide the overloads in cmath due to the issue brought up in this defect report.

    See Is std::abs(0u) ill-formed? for more details on this.

    0 讨论(0)
  • 2021-01-11 18:29

    If you have many template functions causing this problem, you can use the following drop-in replacement:

    #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
    

    Just replace the std::abs calls with util::abs. (Needs c++11.)

    0 讨论(0)
提交回复
热议问题