SFINAE с numeric_limits <T>:: max () в MSVC2017 - PullRequest
3 голосов
/ 15 января 2020

Следующий код:

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;
}

не компилируется на MSVC2017 (ОК для gcc / clang) со следующей ошибкой:

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

Это проблема с моим SFINAE, или это ошибка в MSV C?

Примечание: использование std::numeric_limits<T>::is_signed (или std::is_signed<T>::value) вместо std::numeric_limits<T>::max() прекрасно компилируется:

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;
}

1 Ответ

4 голосов
/ 15 января 2020

Это определенно похоже на ошибку в компиляторе. Он не принимает функции-члены в SFINAE (обратите внимание, что код в вопросе не работает не только для min() / max(), но и для любой функции-члена, такой как epsilon() или lowest()), но он принимает константы-члены , Вы можете использовать следующий простой обходной путь с дополнительным уровнем косвенности, используя struct (если ограничено 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;
}

или переменный шаблон (начиная с 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;
}

Чтобы избежать потенциальных проблем с макросами min / max, определенными в некоторых заголовках (например, windef.h), имя функции можно заключить в скобки:

... = (std::numeric_limits<T>::max)();
...