Являются ли перечисления С++ или без знака? И по расширению безопасно проверять ввод, проверяя, что оно <= ваше максимальное значение, и не указывать >= минимальное значение (при условии, что вы начали с 0 и увеличили на 1)?
Являются ли перечисления С++ подписанными или неподписанными?
Ответ 1
Вы не должны полагаться на какое-либо конкретное представление. Прочтите следующую ссылку . Кроме того, в стандарте указано, что он определяется реализацией, который является интегральным типом в качестве базового типа для перечисления, за исключением того, что он не должен быть больше, чем int, если какое-то значение не может вписаться в int или беззнаковый int.
Вкратце: вы не можете полагаться на перечисление, которое либо подписано, либо без знака.
Ответ 2
Перейдите к источнику. Здесь, что говорит стандарт С++ 03 (ISO/IEC 14882: 2003) в 7.2-5 (Объявления перечисления):
Основной тип перечисления является интегральным типом, который может представлять все значения счетчика, определенные в перечисление. это определяемый реализацией, какой интеграл тип используется в качестве базового типа для перечисления, за исключением того, что базовый тип не должен быть больше чем int, если значение перечислитель не может вписываться в int или unsigned int.
Короче говоря, ваш компилятор выбирает (очевидно, если у вас есть отрицательные числа для некоторых значений ennumeration, они будут подписаны).
Ответ 3
Вы не должны зависеть от их подписания или без знака. Если вы хотите сделать их явно подписанными или неподписанными, вы можете использовать следующее:
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
Ответ 4
Вы не должны полагаться на то, что он подписан или не подписан. В соответствии со стандартом определяется реализация, который является интегральным типом в качестве базового типа для перечисления. Однако в большинстве реализаций это целое число со знаком.
В С++ 0x будут добавлены строго типизированные перечисления, которые позволят вам указать тип перечисления, например:
enum X : signed int { ... }; // signed enum
enum Y : unsigned int { ... }; // unsigned enum
Даже сейчас, однако, может быть достигнута некоторая простая проверка путем использования перечисления в виде переменной или типа параметра следующим образом:
enum Fruit { Apple, Banana };
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit
// even though it has the same value as banana.
Ответ 5
Компилятор может решить, подписаны или нет подписки или нет.
Другим методом проверки перечислений является использование самого перечисления как типа переменной. Например:
enum Fruit
{
Apple = 0,
Banana,
Pineapple,
Orange,
Kumquat
};
enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum
fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana.
Ответ 6
Даже некоторые старые ответы получили 44 upvotes, я, как правило, не согласен со всеми из них. Короче говоря, я не думаю, что мы должны заботиться о underlying type
перечисления.
Во-первых, С++ 03 Тип перечисления - это отдельный тип, не имеющий понятия знака. Поскольку из стандарта С++ 03 dcl.enum
7.2 Enumeration declarations
5 Each enumeration defines a type that is different from all other types....
Итак, когда мы говорим о знаке типа enum, скажем, при сравнении двух операндов enum с использованием оператора <
, мы фактически говорим о неявном преобразовании типа перечисления в некоторый целочисленный тип. Знак этого интегрального типа имеет значение. И при преобразовании перечисления в интегральный тип это утверждение применяется:
9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5).
И, судя по всему, основной тип перечисления не имеет ничего общего с интегральным продвижением. Поскольку стандарт определяет интегральное продвижение следующим образом:
4.5 Integral promotions conv.prom
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long.
Итак, будет ли тип перечисления стать signed int
или unsigned int
зависит от того, может ли signed int
содержать все значения определенных счетчиков, а не базовый тип перечисления.
Смотрите мой вопрос Знак С++ Enum Type Неверный после преобразования в интегральный тип
Ответ 7
В будущем, с С++ 0x, сильно типизированные перечисления будут доступны и будут иметь ряд преимуществ (таких как безопасность типов, явные базовые типы или явное определение области охвата). С этим вы можете быть лучше уверены в знаке типа.
Ответ 8
В дополнение к тому, что другие уже говорили о подписанном /unsigned, вот что говорит стандарт о диапазоне перечисляемого типа:
7.2 (6): "Для перечисления, где e (min) является наименьшим перечислителем, а e (max) является наибольшим, значения перечисления являются значениями базового типа в диапазоне b (min) до b (max), где b (min) и b (max) являются соответственно наименьшими и наибольшими значениями наименьшего битового поля, которые могут хранить e (min) и e (max). Можно определить перечисление, которое имеет значения, не определенные каким-либо из его счетчиков."
Итак, например:
enum { A = 1, B = 4};
определяет перечисляемый тип, где e (min) равно 1, а e (max) равно 4. Если базовый тип является подписанным int, то наименьшее требуемое битовое поле имеет 4 бита, и если ints в вашей реализации являются двумя дополнениями, допустимый диапазон перечисления - от -8 до 7. Если базовый тип не имеет знака, то он имеет 3 бита, а диапазон - от 0 до 7. Проверяйте свою документацию компилятора, если вам это интересно (например, если вы хотите отличать целые значения, отличные от перечисления для перечисляемого типа, то вам нужно знать, находится ли значение в диапазоне перечисления или нет - если не полученное значение перечисления не указано).
Являются ли эти значения допустимыми для вашей функции, может быть другой проблемой, независимо от того, являются ли они допустимыми значениями перечисленного типа. Вероятно, ваш контрольный код беспокоится о первом, а не последнем, и поэтому в этом примере, по крайней мере, нужно проверить >= A и <= B.
Ответ 9
Проверьте это с помощью std::is_signed<std::underlying_type
+ std::is_signed<std::underlying_type
умолчанию int
https://en.cppreference.com/w/cpp/language/enum подразумевает:
main.cpp
#include <cassert>
#include <iostream>
#include <type_traits>
enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};
int main() {
// Implementation defined, let find out.
std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;
// Guaranteed. Scoped defaults to int.
assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));
// Guaranteed. We set it ourselves.
assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}
Скомпилируйте и запустите:
g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main
Выход:
0
Протестировано на Ubuntu 16.04, GCC 6.4.0.