Решение без приведения в действие - использовать переключатель. Однако вы можете сгенерировать псевдопереключатель, используя шаблоны. Принцип заключается в рекурсивной обработке всех значений перечисления с использованием списка шаблонов (или пакета параметров). Итак, вот 3 метода, которые я нашел.
Тестовое перечисление:
enum class Fruit
{
apple,
banana,
orange,
pineapple,
lemon
};
Fruit& operator++(Fruit& f)
{
switch(f)
{
case Fruit::apple: return f = Fruit::banana;
case Fruit::banana: return f = Fruit::orange;
case Fruit::orange: return f = Fruit::pineapple;
case Fruit::pineapple: return f = Fruit::lemon;
case Fruit::lemon: return f = Fruit::apple;
}
}
template<typename E, E v>
struct EnumValue
{
static const E value = v;
};
template<typename h, typename t>
struct StaticList
{
typedef h head;
typedef t tail;
};
template<typename list, typename first>
struct CyclicHead
{
typedef typename list::head item;
};
template<typename first>
struct CyclicHead<void,first>
{
typedef first item;
};
template<typename E, typename list, typename first = typename list::head>
struct Advance
{
typedef typename list::head lh;
typedef typename list::tail lt;
typedef typename CyclicHead<lt, first>::item next;
static void advance(E& value)
{
if(value == lh::value)
value = next::value;
else
Advance<E, typename list::tail, first>::advance(value);
}
};
template<typename E, typename f>
struct Advance<E,void,f>
{
static void advance(E& value)
{
}
};
/// Scalable way, C++03-ish
typedef StaticList<EnumValue<Fruit,Fruit::apple>,
StaticList<EnumValue<Fruit,Fruit::banana>,
StaticList<EnumValue<Fruit,Fruit::orange>,
StaticList<EnumValue<Fruit,Fruit::pineapple>,
StaticList<EnumValue<Fruit,Fruit::lemon>,
void
> > > > > Fruit_values;
Fruit& operator++(Fruit& f)
{
Advance<Fruit, Fruit_values>::advance(f);
return f;
}
template<typename E, E first, E head>
void advanceEnum(E& v)
{
if(v == head)
v = first;
}
template<typename E, E first, E head, E next, E... tail>
void advanceEnum(E& v)
{
if(v == head)
v = next;
else
advanceEnum<E,first,next,tail...>(v);
}
template<typename E, E first, E... values>
struct EnumValues
{
static void advance(E& v)
{
advanceEnum<E, first, first, values...>(v);
}
};
/// Scalable way, C++11-ish
typedef EnumValues<Fruit,
Fruit::apple,
Fruit::banana,
Fruit::orange,
Fruit::pineapple,
Fruit::lemon
> Fruit_values11;
Fruit& operator++(Fruit& f)
{
Fruit_values11::advance(f);
return f;
}
(старая версия C ++ 11)
Вы можете расширить его, добавив некоторый препроцессор, чтобы избавиться от необходимости повторять список значений.
person
Synxis
schedule
16.03.2013
enum class
до исходногоenum
. Мне это кажется странным - какой смысл вводить новый интегральный тип, основанный на числовом значении, но без встроенной поддержки операций с базовым числовым типом. - person SomeWittyUsername   schedule 16.03.2013std::set
) для преодоления проблемenum
. В таком случае почему бы не работать напрямую сstd::set
вместоenum
? - person SomeWittyUsername   schedule 16.03.2013enum
есть свои проблемы, ноenum class
решает их, вводя вместо этого другие проблемы - person SomeWittyUsername   schedule 16.03.2013enum class
. Вся цель этого состоит в том, чтобы не неявно преобразовывать в целое число. Чтобы не рассматривать его как целочисленный тип. Следовательно, если вы хотите выполнить над ним определенные целочисленные операции, вы должны определить их самостоятельно. - person Nicol Bolas   schedule 16.03.2013enum
. В этом случае проще использоватьenum
. Во-вторых, я не запрашиваю преобразование в целочисленный тип. Я прошу выполнить итерацию (например) по диапазону допустимых значений без обращения или использования каким-либо образом базового целочисленного типа. - person SomeWittyUsername   schedule 16.03.2013enum class
до исходныхenum
- нет. Преимуществоenum class
в том, что он не неявно преобразуется в целочисленный тип, а не в том, что он не может быть преобразован в целочисленный тип. Если вы хотите рассматривать данныйenum class
как интегральный тип, вы можете сделать это и можете сделать это явно внутри своегоenum class
интерфейса. Да, добавление итераций по элементам и подобной поддержки на языке было бы неплохо, но был добавленenum class
, потому что это было и полезно, и легко. - person Yakk - Adam Nevraumont   schedule 16.03.2013enum class
(даже с приведениями)? Может быть, это только я, но определениеenum class
мне кажется недоработанным. Это типобезопасный, но менее полезный. Он эффективно разрешает сочетание двух разных типов (что очень важно), но также удаляет все неявно поддерживаемые операции стандартных перечислений (кроме сравнения). Да,enum
также не поддерживает итерацию по несмежному диапазону, но сenum class
удаляется даже итерация по непрерывному диапазону. - person SomeWittyUsername   schedule 16.03.2013enum class
к базовому типу невозможно или нежелательно. Вам лично это не нравится: но это не дизайнenum class
. Вenum class
вы можете получить доступ к базовому типу в любой момент через приведение, и это является частью дизайна. Доступ к операторам базового типа не удаляется, это просто больше не происходит неявно. И несмежныеenum
s? Если вы не приведетеenum
к базовому типу, значениеenum
не будет означать ничего. - person Yakk - Adam Nevraumont   schedule 16.03.2013enum class
- это абстракция языка более высокого уровня. Фундаментальная часть любой абстракции - скрыть технические детали, не относящиеся к клиенту. Если я хочу представить набор фруктов как {яблоко, банан, лимон}, мне не очень интересно добавлять 1 к базовой реализации apple, чтобы добраться до банана. Я использую его для выполнения операций на том же уровне, что и определение моего типа. Вот почему я использую абстракции - чтобы не разбираться с лежащими в основе техническими деталями. Но сenum class
я все равно вынужден с ними иметь дело. Я вижу здесь противоречие. - person SomeWittyUsername   schedule 16.03.2013enum class
не обязательно. Но кто-то, реализующийoperator++
наenum class
, является частью реализации и должен возиться с деталями реализации. Обратите внимание, что не каждыйenum class
ограничен значениями внутри{}
- вы можете написать битовое поле, которое переопределяет|&^~
, а алгебраическое замыкание - все допустимые элементыenum class
. Для такого типа следующаяenum
операция недопустима.enum class
просто позволяет разработчику выбирать, когда рассматривать его как базовый тип, он не блокирует доступ. - person Yakk - Adam Nevraumont   schedule 17.03.2013enum class
в другом свете. Я рассматриваю это как отдельный целочисленный перечислительный тип. Так же, как операции сdouble
не требуют никаких операций сint
или любым другим интегральным типом, я ожидаю, что операции сenum class
будут вести себя одинаково в этом аспекте. - person SomeWittyUsername   schedule 17.03.2013