LaVOZs

The World’s Largest Online Community for Developers

'; c++ - SFINAE with numeric_limits<T>::max() on MSVC2017 - LavOzs.Com

The following code:

template <typename T, typename U>
typename std::enable_if<
    std::numeric_limits<T>::max() == std::numeric_limits<U>::max(),
    bool>::type
same_max() {
    return true;
}

template <typename T, typename U>
typename std::enable_if<
    std::numeric_limits<T>::max() != std::numeric_limits<U>::max(),
    bool>::type
same_max() {
    return false;
}

doesn't compile on MSVC2017 (OK on gcc/clang), with the following error:

error C2995: 'std::enable_if<,bool>::type same_max(void)': function template has already been defined

Is this a problem with my SFINAE, or is this a bug in MSVC?

Note: using std::numeric_limits<T>::is_signed (or std::is_signed<T>::value ) instead of std::numeric_limits<T>::max() compiles fine:

template <typename T, typename U>
typename std::enable_if<
    std::is_signed<T>::value == std::is_signed<U>::value,
    bool>::type
same_signedness() {
    return true;
}

template <typename T, typename U>
typename std::enable_if<
    std::is_signed<T>::value != std::is_signed<U>::value,
    bool>::type
same_signedness() {
    return false;
}

This definitely looks like a bug in the compiler. It doesn't accept member functions in SFINAE (note that the code in the question fails not only for min()/max(), but for any member function like epsilon() or lowest()), but it does accept member constants. You can use the following simple workaround with an additional level of indirection using struct (if limited to C++11):

template<typename T>
struct get_max {
    static constexpr T value = std::numeric_limits<T>::max();
};

template <typename T, typename U>
typename std::enable_if<get_max<T>::value == get_max<U>::value, bool>::type
same_max() {
    return true;
}

template <typename T, typename U>
typename std::enable_if<get_max<T>::value != get_max<U>::value, bool>::type
same_max() {
    return false;
}

or a variable template (since C++14):

template<typename T>
inline constexpr T get_max_v = std::numeric_limits<T>::max();

template <typename T, typename U>
std::enable_if_t<get_max_v<T> == get_max_v<U>, bool>
same_max() {
    return true;
}

template <typename T, typename U>
std::enable_if_t<get_max_v<T> != get_max_v<U>, bool>
same_max() {
    return false;
}

To avoid potential problems with min/max macros defined in some headers (like windef.h), the function name can be parenthesized:

... = (std::numeric_limits<T>::max)();
Related
Is the “lazy man's enable_if” legal C++?
Compile error by using enable_if for SFINAE
SFINAE expression fails to compile with clang
Member function template selection and SFINAE
Why this SFINAE snippet is not working in g++, but working in MSVC?
Why do my SFINAE expressions no longer work with GCC 8.2?
Does the C++ standard allow for an uninitialized bool to crash a program?
What's wrong with my SFINAE?: Testing Supported Operators