Enumerations for flags (bit vectors)

M

Marcel Müller

I have quite often the following demand:

An integral parameter to a function or object contains a bit vector with
flags. But I do not want to use the generic type int for this purpose.
Mostly because it prevents the compiler from checking types more strictly.

As work-around I currently use a code fragment like the one shown below.
But this uses a macro.

The question is: is there a more C++ like way for this purpose that does
not demand on macros?


#define FLAGSATTRIBUTE(T) \
inline static T operator|(T l, T r) \
{ return (T)((unsigned)l|r); } \
inline static T operator&(T l, T r) \
{ return (T)((unsigned)l&r); } \
inline static T& operator|=(T& l, T r) \
{ return l = (T)((unsigned)l|r); } \
inline static T& operator&=(T& l, T r) \
{ return l = (T)((unsigned)l&r); } \
inline static T operator*(bool l, T r) \
{ return (T)(l*(unsigned)r); } \
inline static T operator*(T l, bool r) \
{ return (T)((unsigned)l*r); } \
inline static T operator~(T a) \
{ return (T)~(unsigned)a; }


class MyObject
{public:
enum Flag
{ Flag_None = 0x00,
Flag_1 = 0x01,
Flag_2 = 0x02,
Flag_3 = 0x04
//...
};

Flag flags;
//...
};
FLAGSATTRIBUTE(MyObject::Flag)


// valid expressions:

MyObject o;
int i;
o.flags = MyObject::Flag_None;
o.flags |= MyObject::Flag_2;
o.flags = (i == 7) * MyObject::Flag_3;
o.flags &= ~MyObject::Flag_1;

// invalid expressions
o.flags = 0;
o.flags = i;
o.flags = MyObject::Flag_1 + MyObject::Flag_2;


Marcel
 
G

gnuyuva

I have quite often the following demand:

The question is: is there a more C++ like way for this purpose that does
not demand on macros?

#define FLAGSATTRIBUTE(T) \
inline static T operator|(T l, T r) \
{ return (T)((unsigned)l|r); } \

class MyObject
{public:
enum Flag
{ Flag_None = 0x00,
Flag_1 = 0x01,
Flag_2 = 0x02,
Flag_3 = 0x04
//...
};

Flag flags;
//...};

FLAGSATTRIBUTE(MyObject::Flag)

// valid expressions:

Encapsulate Flag a class.
class Flag
{
// All your operations.
int _flag;
};

The main issue which I observer from your code is:
All those "#define FLAGSATTRIBUTE(T)" definitions.
Consider:
o.flags |= MyObject::Flag_2;
o.flags &= ~MyObject::Flag_1;

They are affecting o.flags and storing the values which are not true
enums.

Also,
if
o.flags = MyObject::Flag_1 + MyObject::Flag_2; this stmt is invalid, then
o.flags |= MyObject::Flag_2;
this stmt should also be invalid.
 
G

Gianni Mariani

Marcel said:
I have quite often the following demand:

An integral parameter to a function or object contains a bit vector with
flags. But I do not want to use the generic type int for this purpose.
Mostly because it prevents the compiler from checking types more strictly.

As work-around I currently use a code fragment like the one shown below.
But this uses a macro.

The question is: is there a more C++ like way for this purpose that does
not demand on macros?

Austria C++ has an another way to do this. Still uses macros tho !

see:
http://austria.svn.sourceforge.net/viewvc/austria/src/austria/code/at_attr_mask.h?view=markup

#define FLAGSATTRIBUTE(T) \
inline static T operator|(T l, T r) \
{ return (T)((unsigned)l|r); } \

Not an appropriate place for casts - don't do casts !
inline static T operator&(T l, T r) \
{ return (T)((unsigned)l&r); } \
inline static T& operator|=(T& l, T r) \
{ return l = (T)((unsigned)l|r); } \
inline static T& operator&=(T& l, T r) \
{ return l = (T)((unsigned)l&r); } \
inline static T operator*(bool l, T r) \
{ return (T)(l*(unsigned)r); } \
inline static T operator*(T l, bool r) \
{ return (T)((unsigned)l*r); } \
inline static T operator~(T a) \
{ return (T)~(unsigned)a; }

In the austria AttrMask system, it uses a base class so that this kind
of code works for all attrs.

OK - so you can do everything you're doing here without the use of
macros. The Austria C++ methodology has the feature of allowing you to
define compile time errors for "illegal" combinations of flags. That's
the only reason you'd use Austria AttrMask over a simpler type managed
methodology.

mmm the code below is an alternative -

template <typename T>
struct Flag
{

typedef typename T::FlagEnum FlagEnum;

Flag union( const Flag & rhs )
{
return Flag(value | rhs.value);
}

protected:
Flag( const FlagEnum & i_value )
: value(i_value)
{}

etc ...

private:
const FlagEnum value;
};

inline static Flag<T> operator|(const Flag<T> & l, const Flag<T> & r)
{ return l.union(r); }

etc ...


template <typename T, typename T::FlagEnum V>
struct FlagValue : Flag<T>
{
FlagValue()
: Flag<T>(V)
{}
};

class MyObject
{public:
enum FlagEnum
{ Flag_None = 0x00,
Flag_1 = 0x01,
Flag_2 = 0x02,
Flag_3 = 0x04
//...
};

Flag<MyObject> flags;
//...
};

// these have to declared in a header and defined in a source file.
const Flag<MyObject> & Flag_None =
FlagValue<MyObject,MyObject::Flag_None>();

const Flag<MyObject> & Flag_1 = FlagValue<MyObject,MyObject::Flag_None>();

MyObject o;

o.flags = Flag_None | Flag_1;

This is a start at least - I think now there might not need to be the
const static flag decl - I'll let you play with that one - if you have
some more q's let me know.
 
J

James Kanze

I have quite often the following demand:
An integral parameter to a function or object contains a bit
vector with flags. But I do not want to use the generic type
int for this purpose. Mostly because it prevents the compiler
from checking types more strictly.
As work-around I currently use a code fragment like the one
shown below. But this uses a macro.
The question is: is there a more C++ like way for this purpose
that does not demand on macros?

Yes. Write the code out in full each time:).

Seriously, I use a small program which parses the C++ enum
declarations, and generates the operators. But it ends up
generating pretty much what your macros do. (I originally wrote
the parser to generate string<-->enum value conversions. Once I
had it, however, it was easy to add the generation of
operators.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top