целое число проверки - это некоторый элемент класса перечисления (С++ 11)

у меня есть класс enum

enum class Foo { A=1, B=18 , Z=42 };

я хочу проверить, можно ли преобразовать некоторое целое число в Foo. Каким был бы идеальный способ сделать это? это для проверки во время выполнения (целое число еще неизвестно во время компиляции)

Очевидно, я могу сделать это трудным путем (написать функцию bool CheckEnum(Foo); с большим переключателем, возвращающим true для всех случаев, кроме случая по умолчанию), но я надеялся на более элегантный механизм, который позволил бы избежать такого количества написания. MPL или Boost.Preprocessor были бы вполне приемлемым решением, но об одном из них я, к сожалению, очень мало знаю


person lurscher    schedule 22.11.2011    source источник
comment
возможный дубликат Как проверить, действительно ли значение перечисления?   -  person John Zwinck    schedule 22.11.2011
comment
@JohnZwinck, почти; это класс перечисления С++ 11, который предположительно является типобезопасным.   -  person lurscher    schedule 22.11.2011
comment
С++ 11 не дает вам никаких новых возможностей для того, что вы хотите делать. Итак, вы застряли с тем, что есть у другого плаката. Я бы хотел, чтобы у меня были новости получше, правда!   -  person John Zwinck    schedule 22.11.2011
comment
@lurscher: это более безопасно для типов. Но это не магия. Единственный способ поместить значение в переменную enum class, не являющуюся одним из перечислителей, — это разрушить систему типов с помощью приведения типов. Это действительно настолько безопасно для типов, насколько это возможно в C++: если вы играете по правилам, это работает. Если вы начнете приводить случайные целые числа к перечислителю, вы намеренно отказываетесь от своих гарантий.   -  person Nicol Bolas    schedule 22.11.2011


Ответы (3)


Решение этой проблемы состоит в том, чтобы отказаться от перечислений и заменить их некоторыми массивами, созданными с использованием XMACRO.

person EvilTeach    schedule 27.11.2011

Не существует «идеального» способа сделать это. Все способы должны будут включать некоторую ручную работу.

Вам необходимо создать структуру данных, содержащую все допустимые значения. Затем найдите эту структуру данных с нужным вам значением времени выполнения. Для этой цели подойдет std::set или std::unordered_set.

Ваша основная трудность будет заключаться в поддержании этого списка, так как его нужно будет обновлять каждый раз, когда вы меняете свой enum class.

person Nicol Bolas    schedule 22.11.2011

Хорошо, я немного устал от этой проблемы (некоторые из моих перечислений составляют почти 100 элементов), поэтому я решил решить ее с помощью генерации кода, что может быть не для всех, но я понял, что на самом деле это не так. такое большое дело.

В основном я выбрал Python Cog, который позволяет мне вставлять фрагменты Python в комментарии в моих файлах .h и . cpp файлы и автоматически генерировать код. Я использую его в основном как действительно умную императивную систему макросов:

я добавил следующее к Test.h

/*[[[cog
#----------- definitions

import cog

def createCategoryConstants( enumVar , bitShift ):
    categoryIndex = 0
    for cat in enumVar:
        cog.outl(' const unsigned int %s_op_mask = (%d << %d); ' %(cat[0] , categoryIndex , bitShift))
        categoryIndex += 1
    cog.outl('\n\n')

def createMultiCategoryEnum( enumVar , enumTypename ):
    cog.outl(' enum class %s { ' % enumTypename )
    categoryIndex = 0
    for i in enumVar:
        itemIndex = 0
        catName = 'NotExpected'
        remainingCategories = len(enumVar)- categoryIndex - 1
        for j in i:
            if (itemIndex == 0):
                catName = j
                itemIndex = 1
                continue
            enumItemIndex = 0
            for enumItem in j:
                remainingEnums = len(j) - enumItemIndex - 1
                currentLine = ' %s = %s_op_mask | %d ' %(enumItem, catName, enumItemIndex)
                if (remainingCategories != 0 or remainingEnums != 0):
                    currentLine += ' , '
                cog.outl(currentLine)
                enumItemIndex += 1
            itemIndex += 1
        cog.outl('') #empty line to separate categories
        categoryIndex += 1
    cog.outl(' };\n\n')

def createIndexFromEnumFunction( enumVar , enumTypename , functionName ):
    cog.outl('uint32_t %s(%s a) { \n switch (a)\n {' % (functionName , enumTypename) )
    absoluteIndex = 0
    for cat in enumVar:
        elemInCat = 0
        for i in cat:
          if elemInCat != 0:
             for enumItem in i:
               cog.outl('case %s:' % enumItem)
               cog.outl(' return %d; \n' % absoluteIndex)
               absoluteIndex += 1
          elemInCat += 1
    cog.outl(' } \n } \n\n ')


def createMultiEnum( enumVar , enumTypename ):
    createCategoryConstants( enumVar , 4)
    createMultiCategoryEnum( enumVar , enumTypename )
    createIndexFromEnumFunction( enumVar , enumTypename , 'FromOpToIndex' )

#------------- generation

multiEnum =[ ['CatA', ['A1', 'A2' , 'A3_foo']] , ['CatSuper8' , ['Z1_bla' , 'Z10' , 'Z11']] ]

createMultiEnum( multiEnum , 'multiFooEnum')

]]]*/
//[[[end]]]

Затем я добавил вызов Cog на этапе предварительной сборки Makefile:

.build-pre:
# Add your pre 'build' code here...
    python /usr/local/bin/cog.py -I../../../tools/cog/ -r *.h

И результаты отображаются чуть ниже:

]]]*/
 const unsigned int CatA_op_mask = (0 << 4); 
 const unsigned int CatSuper8_op_mask = (1 << 4); 



 enum class multiFooEnum { 
 A1 = CatA_op_mask | 0  , 
 A2 = CatA_op_mask | 1  , 
 A3_foo = CatA_op_mask | 2  , 

 Z1_bla = CatSuper8_op_mask | 0  , 
 Z10 = CatSuper8_op_mask | 1  , 
 Z11 = CatSuper8_op_mask | 2 

 };


uint32_t FromOpToIndex(multiFooEnum a) { 
 switch (a)
 {
case A1:
 return 0; 

case A2:
 return 1; 

case A3_foo:
 return 2; 

case Z1_bla:
 return 3; 

case Z10:
 return 4; 

case Z11:
 return 5; 

 } 
 } 


//[[[end]]]

Итак, теперь моя проверка enum заключается в том, чтобы убедиться, что генерация кода (вызываемая во время компиляции) выполняется правильно.

person lurscher    schedule 27.11.2011
comment
Я видел решение для генерации кода несколько раз. Еще несколько трюков, которые вы можете сделать: преобразовать в/из строк, в/из целочисленных значений (с проверкой/подтверждением, если они недействительны) и заключить их в структуру, автоматически сгенерировать максимальные/недопустимые константы (с согласованным именем для всех ваших перечислений ). Это отличная вещь. - person blais; 08.08.2012