Почему C ++ numeric_limits <enum_type> :: max () == 0? - PullRequest
12 голосов
/ 09 февраля 2012

Вот фрагмент кода, который может показаться, что он будет работать:

#include <cassert>
#include <limits>

enum test { A = 1 };

int main()
{
    int max = std::numeric_limits<test>::max();
    assert(max > 0);
}

Но он не работает как в GCC (4.6.2), так и в clang (2.9) в Linux: max () для типов enum фактически равен нулю! И это остается верным, даже если вы используете спецификатор типа перечисления C ++ 11, чтобы точно сказать, какой тип вы хотите иметь в своем перечислении.

Почему это? А что касается поведения в C ++ 11, это то, что явно требуется? Я не смог найти упоминания об этом в N2347, статье о сильно типизованных перечислениях.

Ответы [ 4 ]

23 голосов
/ 09 февраля 2012

std::numeric_limits специализируется на стандартной библиотеке "для каждого арифметического типа, как с плавающей точкой, так и целого числа, включая bool" (§18.3.2.1 / 2).

Ваше перечисление test равноне один из этих типов, поэтому используется основной шаблон.Его поведение определяется в §18.3.2.3 / 1: «Шаблон numeric_limits<T> по умолчанию должен иметь всех членов, но со значениями 0 или false».

Если вы хотите узнать чертыбазовый тип test, вы можете использовать underlying_type:

std::numeric_limits<std::underlying_type<test>::type>::max()

В качестве альтернативы, вы можете специализировать numeric_limits для test и заставить его возвращать нужные значения.Однако это не очень хорошая идея.

3 голосов
/ 09 февраля 2012

Для неспециализированных версий шаблона max возвращает T().Вы не написали специализацию numeric_limits для своего типа test, поэтому вы получаете реализацию по умолчанию.

1 голос
/ 09 февраля 2012

Из проекта C ++ 11:

В 18.3.2.1 о numeric_limits:

Неарифметические стандартные типы, такие как сложные (26.4.2), не должны иметь специализаций.

И перечисление не является стандартным арифметическим типом.

Затем в неспециализированном шаблоне:

template<class T> class numeric_limits {
    public:
    [...]
    static constexpr bool is_specialized = false;
    static constexpr T max() noexcept { return T(); }
};

То есть, неспециализированная функция max() возвращает инициализированное значение по умолчанию для этого типа, то есть 0.

1 голос
/ 09 февраля 2012

numeric_limits<T> - это обычный шаблон класса, он не связан каким-либо особым образом с компилятором, чтобы узнать о пользовательских enum типах.Если вы посмотрите на файл <limits>, у него есть определение шаблона по умолчанию, которое возвращает нули для всего, и целый набор специфических для типа спецификаций для отдельных типов, возвращающих правильные константы.

Вы можете «подключить» свой enum к numeric_limits, указав спецификацию numeric_limits<test> самостоятельно.Вы можете скопировать один файл для int из <limits> и изменить его в соответствии со своими потребностями.

...