validate integer - это некоторый элемент класса enum (C ++ 11) - PullRequest
8 голосов
/ 22 ноября 2011

У меня есть некоторый класс enum

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

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

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

Ответы [ 3 ]

2 голосов
/ 27 ноября 2011

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

0 голосов
/ 27 ноября 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]]]

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

0 голосов
/ 22 ноября 2011

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

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

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

...