Ответ 1
Вам может потребоваться перегрузить оператор ++
для вашего перечисления, если вы действительно хотите повторить его значения:
Foo& operator++( Foo& f )
{
using UT = std::underlying_type< Foo >::type;
f = static_cast< Foo >( static_cast< UT >( f ) + 1 );
return f;
}
и используйте
for (Foo foo = Foo::First; foo != Foo::Last; ++foo)
{
...
}
Чтобы ответить на вопрос, разрешен ли reinterpret_cast
, все начинается с 5.2.10/1:
5.2.10 Реинтерпретировать литье [expr.reinterpret.cast]
1 Результат выражения
reinterpret_cast<T>(v)
является результатом преобразования выраженияv
в типT
. ЕслиT
является ссылочным типом lvalue или ссылкой rvalue на тип функции, результатом является lvalue; еслиT
является ссылкой rvalue на тип объекта, результатом является xvalue; в противном случае результатом будет выражение prvalue и lvalue-to-rvalue (4.1), array-to-pointer (4.2) и стандартное преобразование функции-to-pointer (4.3) в выраженииv
. Ниже перечислены преобразования, которые могут быть выполнены явно с использованиемreinterpret_cast
. Никакое другое преобразование не может быть выполнено явно с помощьюreinterpret_cast
.
(акцент мой)
Реинтерпретация с использованием ссылок основана на указателях в соответствии с 5.2.10/11:
11 Выражение glval типа
T1
может быть передано типу "ссылка наT2
", если выражение типа "указатель наT1
" может быть явно преобразовано в введите "указатель наT2
" с помощьюreinterpret_cast
. Результат относится к тому же объекту, что и исходное значение glvalue, но с указанным типом. [Примечание. То есть для lvalues ссылочный листингreinterpret_cast<T&>(x)
имеет тот же эффект, что и преобразование*reinterpret_cast<T*>(&x)
со встроенными операторами&
и*
(и аналогично дляreinterpret_cast<T&&>(x)
). - end note] Временное создание не производится, копия не производится, а конструкторы (12.1) или функции преобразования (12.3) не вызываются.
Из этого вытекает вопрос:
reinterpret_cast<int8_t&>(foo)
является ли это законным:
*reinterpret_cast<int8_t*>(&foo)
Следующая остановка - 5.2.10/7:
7 Указатель объекта может быть явно преобразован в указатель объекта другого типа. Когда prvalue
v
типа "указатель наT1
" преобразуется в тип "указатель на cvT2
", результат:static_cast<
cv
T2*>(static_cast<
cv
void*>(v))
, если обаT1
иT2
являются стандартными типами макетов (3.9), а требования к выравниваниюT2
не более строгие, чем тегиT1
, или если один из типов -void
. Преобразование prvalue типа "указатель наT1
" в тип "указатель наT2
" (гдеT1
иT2
являются типами объектов, а требования к выравниваниюT2
не более строгие, чем требованияT1
) и обратно к исходному типу дает исходное значение указателя. Результат любого другого такого преобразования указателя не указан.
Учитывая 3.9/9 как int8_t
, так и ваш тип перечисления являются стандартными типами макета, теперь вопрос преобразуется в:
*static_cast<int8_t*>(static_cast<void*>(&foo))
Здесь вам не повезло. static_cast
определяется в 5.2.9, и нет ничего, что делает вышеупомянутый законным - на самом деле 5.2.9/5 является четким намеком на то, что он является незаконным. Другие предложения не помогают:
- 5.2.9/13 требует
T*
→void*
→T*
, гдеT
должен быть идентичным (исключая cv) - 5.2.9/9 и 5.2.9/10 относятся не к указателям, а значениям
- 5.2.9/11 относится к классам и иерархиям классов
- 5.2.9/12 - о указателях класса
Мое заключение состоит в том, что ваш код
reinterpret_cast<int8_t&>(foo)
не является законным, его поведение не определяется стандартом.
Также обратите внимание, что вышеупомянутые 5.2.9/9 и 5.2.9/10 несут ответственность за внесение кода, который я дал в первоначальном ответе и который вы все еще можете найти наверху.