Developer forums (C::B DEVELOPMENT STRICTLY!) > CodeCompletion redesign

bitwise operation on enum types

(1/2) > >>

ollydbg:
We have enum type definition

--- Code: ---enum TokenKind
{
    // changed in order to reflect the priority
    tkNamespace     = 0x0001,
    tkClass         = 0x0002,
    tkEnum          = 0x0004,
    tkTypedef       = 0x0008, // typedefs are stored as classes inheriting from the typedef'd type (taking advantage of existing inheritance code)
    tkConstructor   = 0x0010,
    tkDestructor    = 0x0020,
    tkFunction      = 0x0040,
    tkVariable      = 0x0080,
    tkEnumerator    = 0x0100,
    tkPreprocessor  = 0x0200,
    tkMacro         = 0x0400,

    // convenient masks
    tkAnyContainer  = tkClass    | tkNamespace   | tkTypedef,
    tkAnyFunction   = tkFunction | tkConstructor | tkDestructor,

    // undefined or just "all"
    tkUndefined     = 0xFFFF
};

--- End code ---

But in some cases, we need a mask, like:

--- Code: ---Token* TokenExists(const wxString& name, const Token* parent = 0, short int kindMask = 0xFFFF);

--- End code ---

Note, here the mask type is: short int, TokenKind is not allowed here, because if you put here, then some code like:


--- Code: ---TokenExists(, , tkTypedef | tkClass);
--- End code ---

will compiler error, like: error: invalid conversion from 'int' to enum type TokenKind.

There are many discussion:
on enum and bitwise operation
How to use enums as flags in C++?
and more.

So, what's your opinion on this, I think using a TokenKind for the function argument is better.
Do we use:

--- Code: ---TokenExists(, , static_cast<TokenKind>(tkTypedef | tkClass));
--- End code ---

Or, we can define some bitwise operator like in this post http://stackoverflow.com/a/1448478/154911

--- Code: ---enum AnimalFlags
{
    HasClaws = 1,
    CanFly =2,
    EatsFish = 4,
    Endangered = 8
};

inline AnimalFlags operator|(AnimalFlags a, AnimalFlags b)
{return static_cast<AnimalFlags>(static_cast<int>(a) | static_cast<int>(b));}
...

--- End code ---

ollydbg:
I see some code in CC use type conversion, like:

--- Code: ---            else if (command == cmdSearchAll)
                tree->FindMatches(args, result, true, false, TokenKind(kindToSearch));
            else
                tree->FindMatches(args, result, true, false, TokenKind(tkAnyContainer|tkEnum));
--- End code ---
The function prototype is:

--- Code: ---   size_t FindMatches(const wxString& query, TokenIdxSet& result, bool caseSensitive, bool is_prefix, TokenKind kindMask = tkUndefined);
--- End code ---

thomas:
It is strictly legal for an enumeration value to be a value that is not part of the enumeration definition, as long as it fits the storage size. Therefore, I would just add either an operator| or a conversion operator. Preferrably the former, as it is more type-safe (a conversion operator would totally anihilate the type system, since it converts any integer, not just one composed of enum values);

Something like TokenKind operator|(TokenKind a, TokenKind b) { return (TokenKind) (a|b); } should work.

oBFusCATed:

--- Quote from: thomas on November 15, 2013, 05:01:12 pm ---It is strictly legal for an enumeration value to be a value that is not part of the enumeration definition, as long as it fits the storage size.

--- End quote ---
Can you quote the standard?

@ollydbg:
I don't see where the problem with using short int parameter is coming from?

This compiles without errors on GCC 4.4

--- Code: ---enum TokenKind
{
    // changed in order to reflect the priority
    tkNamespace     = 0x0001,
    tkClass         = 0x0002,
    tkEnum          = 0x0004,
    tkTypedef       = 0x0008, // typedefs are stored as classes inheriting from the typedef'd type (taking advantage of existing inheritance code)
    tkConstructor   = 0x0010,
    tkDestructor    = 0x0020,
    tkFunction      = 0x0040,
    tkVariable      = 0x0080,
    tkEnumerator    = 0x0100,
    tkPreprocessor  = 0x0200,
    tkMacro         = 0x0400,

    // convenient masks
    tkAnyContainer  = tkClass    | tkNamespace   | tkTypedef,
    tkAnyFunction   = tkFunction | tkConstructor | tkDestructor,

    // undefined or just "all"
    tkUndefined     = 0xFFFF
};

void func(int a, short int b=tkUndefined) {
int c;
c=a+b;
}
int main() {
func(1, tkTypedef | tkClass);
return 0;
}

--- End code ---

ollydbg:
@OBF
Yes, the code builds OK.
I don't know "short int" has the same sizeof TokenKind.
Currently, the largest enumerator in TokenKind is 0xFFFF (16bit), what about "short int"? People will confused, but when we put TokenKind in the function parameter, they don't worry about different types.

Navigation

[0] Message Index

[#] Next page

Go to full version