Почему С++ numeric_limits <enum_type>:: max() == 0?

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

#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() для типов перечислений на самом деле равен нулю! И это остается правдой, даже если вы используете спецификатор типа перечисления С++ 11, чтобы вкратце сказать, какой тип вы хотите, чтобы ваш enum имел.

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

Ответ 1

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 и вернуть значения, которые вы хотите. Однако это не очень хорошая идея.

Ответ 2

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

Ответ 3

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

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

Ответ 4

Из проекта С++ 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.