Почему С++ 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.