2012-02-18 3 views
28

У меня есть переменная, объявленная как:Как узнать базовый тип перечисления класса?

enum class FooEnum: uint64_t {} 

, и я хотел бы, чтобы бросить его базового типа, но я не хочу жёстко базового типа. Например, примерно следующее:

FooEnum myEnum; 
uint64_t * intPointer = (underlying_typeof(myEnum))&myEnum; 

Возможно ли это?

+0

http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast литье, в частности, динамический – L7ColWinters

+5

@ L7ColWinters ' dynamic_cast' не может помочь. Не позволяйте ключевому слову 'class' и': uint64_t 'вводить вас в заблуждение, думая, что области и перечисления типов перечислены аналогично наследованию класса. –

ответ

33

Вы можете использовать это:

  • std::underlying_type шаблон класса знать базовый тип перечисления.

doc говорит,

Определяет член typedef типа типа, который является базовым типом для перечисления Т.

Таким образом, вы должны быть в состоянии сделать это:

#include <type_traits> //include this 

FooEnum myEnum; 
auto pointer = static_cast<std::underlying_type<FooEnum>::type*>(&myEnum); 
+2

Я удалил свой ответ, а затем поддержал ваш. Но вы еще не компилируете свой ответ, когда я пишу это. Поэтому я передумал и восстановил свой ответ. ;-) –

+0

Будет ли 'static_cast' работать? У меня создалось впечатление, что никакие здравомыслящие касты не будут работать над классом enum. –

16

Ваш g Усиленный синтаксис удивительно близок. Вы ищете std::underlying_type в <type_traits>:

#include <type_traits> 
#include <cstdint> 

enum class FooEnum: std::uint64_t {}; 

int main() 
{ 
    FooEnum myEnum; 
    uint64_t* intPointer = (std::underlying_type<FooEnum>::type*)&myEnum; 
} 
+0

Так близко. По-видимому, было выбрано подходящее имя. :) – Kyle

7

Оба Visual C++ 10,0 и MinGW г ++ 4.6.1 не хватает std::underlying_type, но и принять этот код:

template< class TpEnum > 
struct UnderlyingType 
{ 
    typedef typename conditional< 
     TpEnum(-1) < TpEnum(0), 
     typename make_signed<TpEnum>::type, 
     typename make_unsigned<TpEnum>::type 
     >::type T; 
}; 
+0

@ Cheersandhth.-Alf @Grizzly: Тем не менее, приведения 'TpEnum (-1)' и 'TpEnum (0)' * могут * иметь UB: 5.2.9 «Static cast», в пункте 10 говорится: «Значение интеграла или тип перечисления могут быть явно преобразованы в тип перечисления. Значение не изменяется, если исходное значение находится в пределах диапазона значений перечисления (7.2). В противном случае результирующее значение не определено (и может быть не в этом диапазоне) ». –

+1

@Joker_vD: не указано не UB. –

2

Вот другой подход, когда basic_type нет. Этот метод не пытается обнаружить подписанность перечисления, просто дайте вам тип того же размера, которого более чем достаточно для многих ситуаций.

template<int> 
class TIntegerForSize 
{ 
    typedef void type; 
}; 

template<> 
struct TIntegerForSize<1> 
{ 
    typedef uint8_t type; 
}; 

template<> 
struct TIntegerForSize<2> 
{ 
    typedef uint16_t type; 
}; 

template<> 
struct TIntegerForSize<4> 
{ 
    typedef uint32_t type; 
}; 

template<> 
struct TIntegerForSize<8> 
{ 
    typedef uint64_t type; 
}; 

template<typename T> 
struct TIntegerForEnum 
{ 
    typedef typename TIntegerForSize<sizeof(T)>::type type; 
}; 

Использование:

enum EFoo {Alpha, Beta}; 
EFoo f = Alpha; 
TIntegerForEnum<EFoo>::type i = f; 
TIntegerForEnum<decltype(f)>::type j = f; 
Смежные вопросы