validate integer is some enum class item (C++11)

夙愿已清 提交于 2019-12-08 17:39:45

问题


i have some enum class

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

i want to check if some integer can be converted into a Foo. What would be the ideal way to do this? this is for runtime check (the integer is not known yet at compile-time)

Obviously i can do this the hard way (write a function bool CheckEnum(Foo); with a big-ass switch returning true for all cases except the default one), but i was hoping a more elegant mechanism that avoided so much writing. MPL or Boost.Preprocessor would be a perfectly acceptable solution, but one of which i sadly know very little about


回答1:


A solution to this problem is to ditch the enums, and replace it with some arrays which are created using XMACROs.




回答2:


There is no "ideal" way to do it. All ways are going to have to involve some manual work.

You need to create a data structure that contains all of the acceptable values. Then search that data structure with the runtime value you need. A std::set or std::unordered_set would be adequate for this purpose.

Your main difficulty will be in maintaining that list, as it will need to be updated every time you change your enum class.




回答3:


Ok i'm a little bit fed up with this issue (some of my enums are nearly 100 items) so i decided to tackle it with code generation, which might not be everyone's cup of tea, but i've realised that is really no such a big deal.

Basically i went for Python Cog, which allows me to embed python snippets inside comments in my .h and .cpp files and auto-generate code. I use it basically like a really smart, imperative macro system:

i added the following to 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]]]

Then i added cog invocation in my Makefile pre-build step:

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

And the results show up just below:

]]]*/
 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]]]

So, now my enum validation is about making sure the code generation (invoked at compile time) is done correctly



来源:https://stackoverflow.com/questions/8221745/validate-integer-is-some-enum-class-item-c11

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!