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

有帮助吗?

解决方案 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

其他提示

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

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top