• Forum
  • Lounge
  • Elegant Way to Use Enum Classes as Flags

 
Elegant Way to Use Enum Classes as Flags?

I'm trying to figure out a way to use the scoped enumeration feature defined in C++11.

In my project, I have something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enum class InputElementName
{
    BINORMAL,
    BLENDINDICES,
    BLENDWEIGHT,
    COLOR,
    NORMAL,
    POSITION,
    POSITIONT,
    PSIZE,
    TANGENT,
    TEXCOORD,
    COLOR,
    FOG,
    TESSFACTOR,
};


I want to use it in a manner such as this:
1
2
3
4
5
RBE::InputElementDescription input_elements[] =
{
    { RBE::InputElementName::POSITION, 0, RBE::Format::RGBA_F32, 0, 0,  RBE::InputElementClass::VERTEX, 0 },
    { RBE::InputElementName::COLOR,    0, RBE::Format::RGBA_F32, 0, 16, RBE::InputElementClass::VERTEX, 0 }
};


I'm trying to use this as a sort of more verbose way to use flags, and also to remove littering of namespaces by not using them. Unfortunately, C++11 doesn't allow a lot of operations you could perform with non-enum flag types, so I have to try to find a (hopefully not very hacky) way around this. Maybe I could use a template-based solution to get around this? (I'd prefer not to use a macro for this, as they just pollute global namespace, which is exactly the type of thing I'm trying to avoid)

I guess the simplest way to do this all would be to do something like:
1
2
3
4
5
6
7
struct InputElementName
{
    enum
    {
        BINORMAL, // Etc
    };
};
But that's pretty ugly and it can't actually be used as a type.

Thanks in advance.
Last edited on
If you're going to use old-style flags and OR them together, you should probably just use old-style enums too.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace InputElementName
{
    enum type //so you can use InputElementName::type
    {
        BINORMAL     = 0b1,
        BLENDINDICES = 0b10,
        BLENDWEIGHT  = 0b100,
        COLOR        = 0b1000,
        NORMAL       = 0b10000,
        POSITION     = 0b100000,
        POSITIONT    = 0b1000000,
        PSIZE        = 0b10000000,
        TANGENT      = 0b100000000,
        TEXCOORD     = 0b1000000000,
//      COLOR        = 0b10000000000, //defined again??
        FOG          = 0b100000000000,
        TESSFACTOR   = 0b1000000000000,
    };
}
Sure, there's no type safety, but you're ORing together flags...?

In an ideal world I'd use a std::set of an enum struct type, but I'm worried about efficiency. You could do some template metaprogramming though...
Last edited on
THis is only if enum values can be mixed together.
Last edited on
Bleh, I just realized that I'm talking about the wrong enumeration. I really meant something like this:
1
2
3
4
5
6
7
8
9
enum class UsageFlags
{
    STATIC   = 0x00000001,
    DYNAMIC  = 0x00000002,
    
    UNORDERED_ACCESS   = 0x0008,
    BYTE_ADDRESS_BUFFER = 0x0020
    // Etc
};

and:
vb = rbe->CreateVertexBuffer(RBE::UsageFlags::DYNAMIC, sizeof(VertexPC) * 3);
Unfortunately it's being defined as a type that's local to a class, so I can't create a namespace in there. I assume my only option is the struct + enum workaround?
Last edited on
1
2
3
4
5
6
7
8
9
10
class RBE {
public:
    struct UsageFlags {
        enum type {
            STATIC =1,
            DYNAMIC,
            UNORDERED_ADDRESS =8
        };
    };
};
Last edited on
Yeah, that's what I ended up doing, but I just cleaned it up with some macros (but is using macros really "cleaning it?" Lol). Now it's something like:

1
2
3
4
5
6
7
8
9
10
11
12
#define BEGIN_FLAG_TYPE(x) struct x { enum Type{ 
#define END_FLAG_TYPE };};

BEGIN_FLAG_TYPE(UsageFlags)
    STATIC              = 0x00000001,
    DYNAMIC             = 0x00000002,
    
    UNORDERED_ACCESS    = 0x00000008,
    
    BYTE_ADDRESS_BUFFER = 0x00000002,
    // Etc
END_FLAG_TYPE


Thanks guys!
Last edited on
Topic archived. No new replies allowed.