I have an enum like this:
enum ParserMode
{
PM_NONE = 0,
PM_READY = 1, // ready for next col or row, or EOF
PM_EMPTY = 2, // empty cell
PM_CELL = 4, // cell
PM_QCELL = 8, // quoted cell
PM_HEAD = 16, // header cell
};
And elsewhere I want to write something like:
void DoStuff(ParserMode m)
{
if (m & PM_HEAD)
...
else if (m & PM_QCELL)
...
}
...
DoStuff(PM_CELL | PM_EMPTY | PM_HEAD);
But this will not work, because the compiler complains about not being
able to cast between int and ParserMode. So some operator overloading
clears that up:
inline ParserMode operator|(ParserMode p1, ParserMode p2)
{
return (ParserMode)((int)p1 | (int)p2);
};
inline ParserMode operator&(ParserMode p1, ParserMode p2)
{
return (ParserMode)((int)p1 & (int)p2);
};
inline ParserMode operator~(ParserMode p1)
{
return (ParserMode)(~(int)p1);
};
inline ParserMode& operator&=(ParserMode& p1, ParserMode p2) {
p1 = p1 & p2;
return p1;
}
...
...And everything works fine. But, now I need to add another enum, and
I don't want to copy all of these overloaded operators for this other
enum. Is there some way I can share one set of operator overloads
between many enums using templates, macros, or some other trick, or am
I just going about this wrong altogether?
Thanks in advance for any help.
-- Nick
nick wrote:
> inline ParserMode operator|(ParserMode p1, ParserMode p2)
> {
> return (ParserMode)((int)p1 | (int)p2);
> };
> ...
you won't come around to use macros in this case.
E.g.
#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; }
and possibly
#define CLASSFLAGSATTRIBUTE(T) \
inline friend T operator|(T l, T r) \
{ return (T)((unsigned)l|r); } \
inline friend T operator&(T l, T r) \
{ return (T)((unsigned)l&r); } \
inline friend T& operator|=(T& l, T r) \
{ return l = (T)((unsigned)l|r); } \
inline friend T& operator&=(T& l, T r) \
{ return l = (T)((unsigned)l&r); } \
inline friend T operator*(bool l, T r) \
{ return (T)(l*(unsigned)r); } \
inline friend T operator*(T l, bool r) \
{ return (T)((unsigned)l*r); } \
inline friend T operator~(T a) \
{ return (T)~(unsigned)a; }
for private or protected nested enums.
enum ParserMode
{
PM_NONE = 0,
PM_READY = 1, // ready for next col or row, or EOF
PM_EMPTY = 2, // empty cell
PM_CELL = 4, // cell
PM_QCELL = 8, // quoted cell
PM_HEAD = 16, // header cell
};
FLAGSATTRIBUTE(ParserMode)
The result is similar than the FlagsAttribute class in DotNET.
Marcel
Yeah, it is a common "problem" too bad the language did not look for that
when removing the int->enum conversion; the listed operations currently
promote the enum to int (or bigger) create the result and it stays that
type. Instead of vorking natively on the enum and produce that type. :(
At least for | and &.
I never used ~ that way, as it may not work. The rule is that the
implementation type for enum must represent all the enumerators and their |.
so the value of your ~ is not predictable (unless you can force the compiler
to use some fixed type.
To create the missing operators I use a macro that takes enum name as param
and expands to text similar to yours. And just add it right after the enum
definition if it is used that way, saves redundancy and provides kinda
documantation of purpose too.
Hi Nick
I think the following code helps you
enum ParserMode {
PM_NONE = 0,
PM_READY = 1, // ready for next col or row, or EOF
PM_EMPTY = 2, // empty cell
PM_CELL = 4, // cell
PM_QCELL = 8, // quoted cell
PM_HEAD = 16, // header cell
};
enum ScannerMode { // another enum
SM_NONE = 0,
SM_READY = 1,
SM_EMPTY = 2,
SM_CELL = 4,
SM_QCELL = 8,
SM_HEAD = 16,
};
template<class ENUM_TYPE>
ENUM_TYPE operator|(ENUM_TYPE e1, ENUM_TYPE e2)
{
int i1 = e1; // implicit type conversion
int i2 = e2;
return ENUM_TYPE(i1 | i2);
}
template<class ENUM_TYPE>
ENUM_TYPE operator&(ENUM_TYPE e1, ENUM_TYPE e2)
{
int i1 = e1; // implicit type conversion
int i2 = e2;
return ENUM_TYPE(i1 & i2);
}
template<class ENUM_TYPE>
ENUM_TYPE operator~(ENUM_TYPE e)
{
int i = e; // implicit type conversion
return ENUM_TYPE(~i);
}
int main()
{
ScannerMode s1 = SM_NONE, s2 = SM_HEAD;
s1 = s1 | s2;
ParserMode p1 = PM_NONE, p2 = p1;
p1 = ~p1;
p2 = ~(p2 & p1);
return 0;
}
Regards,
-- Saeed Amrollahi
>>
template<class ENUM_TYPE>
ENUM_TYPE operator|(ENUM_TYPE e1, ENUM_TYPE e2)
{
int i1 = e1; // implicit type conversion
int i2 = e2;
return ENUM_TYPE(i1 | i2);
}
<<
There is nothing to restrict the arguments here, so this template may pick
up unwanted stuff. (And use of the old-style cast in return instead of
static_cast makes it even more dangerous).
One may use is_enum<ENUM_TYPE>::value to restrict it.
I see what you mean. The code by Nick had the problem too. From point
of C++ Design and Implmentation,
he wanted to share common code between two different enums. For well-
known reasons, I prefer template
over macros. I am not sure, but if I'm not mistaken, in C++0x, the
Scoped enums don't allow the implicit
conversion from enum to int.
regards,
-- Saeed Amrollahi
Marcel, your solution works perfectly. I like how it 'documents' the
enum as being a flag set. I'm using this for now with a few small
additions, but now I'm curious why people seem generally opposed to
macros...
Anyway, I have a few other small questions if you guys are still
interested. Balog, you mentioned the ~ operator would not be
predictable, and it sounds like it's because the way enums are stored
in memory is not predictable?
This makes me wonder if I should cast to unsigned as in Marcel's
example, or signed as in Saeed's example and as I was doing before. Of
course I'll only want to use positive numbers for my flag sets, but
enums seem to handle negative numbers just fine, so I'm not sure what
the right thing to do is here.
So, I guess my question is: is there a way to explicitly store an enum
as an int, or an unsigned int, or whatever, either using a language
construct or some kind of compiler instrucion? I'm using GCC 4.3.
The template stuff may be a bit over my head, but here's how I
understand it: Saeed's solution will work, but it will overload those
operators for all (classes? enums?), not just the flag sets I need
those operators for. Johannes says I can use is_enum<ENUM_TYPE>::value
to fix it so it only affects (enums?) ... is that about right? If so
what are the advantages of that over Marcel's method, other than macro
definitions looking ugly in the source?
Thanks for the help!
-- Nick
errm, if they are flags why not just use '#define'?...
> -- Nick
>I see what you mean. The code by Nick had the problem too. From point
>of C++ Design and Implmentation,
>he wanted to share common code between two different enums. For well-
>known reasons, I prefer template
>over macros.
Me too. But for this case I stand with macros. Global templated operator --
that is way more evil than macros :)
And for this case I want certain operators only for a couple of enums. (bit
operators for those that has masks, increment, addition that I use in state
machine, etc...)
If that is_enum<> actually works it still picks up all the enums, masking
problems where I used an unintended one.
>I am not sure, but if I'm not mistaken, in C++0x, the
>Scoped enums don't allow the implicit
>conversion from enum to int.
Yeah, there are good improvements, class enums do not convert to integrals
implicitly, also you can set a fixed implementation type -- and if you did,
you can forward-declare the enum, and define its enumerators at multiple
places. (IIRC)
You will find it in all accepted standard/guideline books. The most serious
roblem is that macros do not respect scope. And for many applications there
are way better tools -- constants/enums, inline functions, templates...
Though not for everything.
> Anyway, I have a few other small questions if you guys are still
> interested. Balog, you mentioned the ~ operator would not be
> predictable, and it sounds like it's because the way enums are stored
> in memory is not predictable?
Yes, if you have enumerators 0, 1 -- the used type may be char, unsigned
char, short, int, possibly others. Certain use approach can go without
problems, but I'd avoid it unless absolutely needed. If you want it to
remove bits combined with &, rather define a named function doing right
that.
> This makes me wonder if I should cast to unsigned as in Marcel's
> example, or signed as in Saeed's example and as I was doing before. Of
> course I'll only want to use positive numbers for my flag sets, but
> enums seem to handle negative numbers just fine, so I'm not sure what
> the right thing to do is here.
For bit-masks I stick to unsigned operations.
> So, I guess my question is: is there a way to explicitly store an enum
> as an int, or an unsigned int, or whatever, either using a language
> construct or some kind of compiler instrucion? I'm using GCC 4.3.
Probably gcc has a compiler switch to 'treat enums as ints' or like, though
for all of them. Look dox for attribute, rthough don't hold your breath. For
language level control wait C++0x.
> The template stuff may be a bit over my head, but here's how I
> understand it: Saeed's solution will work, but it will overload those
> operators for all (classes? enums?), not just the flag sets I need
> those operators for. Johannes says I can use is_enum<ENUM_TYPE>::value
> to fix it so it only affects (enums?) ... is that about right?
AFAIK is_enum is some boost magic.
#define FLAGS_(T) \
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 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|r; } \
inline static T operator-(T l, T r) \
{ return l&r?(T)((unsigned)l-(unsigned)r):l; } \
inline static T& operator|=(T& l, T r) \
{ return l = l|r; } \
inline static T& operator&=(T& l, T r) \
{ return l = l&r; } \
inline static T& operator+=(T& l, T r) \
{ return l = l+r; } \
inline static T& operator-=(T& l, T r) \
{ return l = l-r; }
> "nick" <nic...@fastmail.fm>
>> Marcel, your solution works perfectly. I like how it 'documents' the
>> enum as being a flag set. I'm using this for now with a few small
>> additions, but now I'm curious why people seem generally opposed to
>> macros...
>
> You will find it in all accepted standard/guideline books. The most
> serious
> roblem is that macros do not respect scope. And for many applications
> there are way better tools -- constants/enums, inline functions,
> templates... Though not for everything.
>
>> The template stuff may be a bit over my head, but here's how I
>> understand it: Saeed's solution will work, but it will overload those
>> operators for all (classes? enums?), not just the flag sets I need
>> those operators for. Johannes says I can use is_enum<ENUM_TYPE>::value
>> to fix it so it only affects (enums?) ... is that about right?
>
You first have to make sure that the type is not an integral type (just
compare it with each and every integral type), and then make sure it's not a
class type, and then test if it converts to one integral type. If that'S the
case, it must be an enum. The book "C++ templates, the complete guide" shows
a possible implementation. I'm trying to remember it here:
// don't let class types convert to the integral types
template<typename T>
struct SlurpUDC {
operator T();
};
typedef char yes[1];
typedef char no[2];
yes &int_(int);
yes &int_(unsigned int);
yes &int_(long);
yes &int_(unsigned long);
no & int_(...);
// if your compiler has it, then long long, unsigned long long
template<typename> struct intt { static bool const value = false; };
#define INTT(X) template<> struct intt<X> { static bool const value = true;
}
INTT(char);
INTT(signed char);
INTT(unsigned char);
INTT(int);
INTT(unsigned int);
INTT(long);
INTT(unsigned long);
INTT(wchar_t);
INTT(bool);
// if your compiler has it, then long long, unsigned long long, and hoping
// that i've not missed one.
C++0x introduces implementation defined integral types that may not match
any of these, but then it also has is_enum, so you don't need to write this
at all, anyway.
template<typename T>
struct is_enum {
static bool const value = sizeof int_(SlurpUDC<T>()) == sizeof(yes)
&& !intt<T>::value;
};
Notice that an enumeration type will promote to one integral type out of the
4 above. That's all i think. Now you can write
template<typename A>
typename enable_if<is_enum<A>::value, A>::type operator|(A a, A b) { ... }
Hope it helps...
> #true;
> }
>
> INTT(char);
> INTT(signed char);
> INTT(unsigned char);
> INTT(int);
> INTT(unsigned int);
> INTT(long);
> INTT(unsigned long);
> INTT(wchar_t);
> INTT(bool);
> // if your compiler has it, then long long, unsigned long long, and hoping
> // that i've not missed one.
>
> C++0x introduces implementation defined integral types that may not match
> any of these, but then it also has is_enum, so you don't need to write
> this at all, anyway.
>
> template<typename T>
> struct is_enum {
> static bool const value = sizeof int_(SlurpUDC<T>()) == sizeof(yes)
> && !intt<T>::value;
> };
>
> Notice that an enumeration type will promote to one integral type out of
> the 4 above. That's all i think. Now you can write
>
> template<typename A>
> typename enable_if<is_enum<A>::value, A>::type operator|(A a, A b) { ... }
>
> Hope it helps...
You may need to introduce special cases in "SlurpUDC" for void, function and
array types. For each of these, there are traits though that can do the work
for you, though. Alternatively, you can instead return "operator T&()",
which i believe will only need a specialization for void.
template<typename T> struct SlurpUDC { operator T&(); };
// definitely won't convert to one of the integral types
template<> struct SlurpUDC<void> { };
template<> struct SlurpUDC<void const> { };
template<> struct SlurpUDC<void volatile> { };
template<> struct SlurpUDC<void const volatile> { };
Put a INTT(short); INTT(unsigned short); and in my tests with GCC, the above
codes work fine for regognizing an enum type.
Then "every integral type" is the weak point -- extensions like long long or
__int64 are widespread, but their knowledge is tied to compiler/version
info...
So until official tr1:: support I don;t consider it a stable point, and
avoid unless very much need some functionality and accept limitation to some
compilers.
> C++0x introduces implementation defined integral types that may not match
> any of these, but then it also has is_enum, so you don't need to write
> this
> at all, anyway.
Well, native type info is a thing we needed much. At least that remains with
the concepts scrapped. :(
> "Johannes Schaub (litb)" <schaub-...@web.de>
>>>> The template stuff may be a bit over my head, but here's how I
>>>> understand it: Saeed's solution will work, but it will overload those
>>>> operators for all (classes? enums?), not just the flag sets I need
>>>> those operators for. Johannes says I can use is_enum<ENUM_TYPE>::value
>>>> to fix it so it only affects (enums?) ... is that about right?
>>>
>>
>> You first have to make sure that the type is not an integral type (just
>> compare it with each and every integral type), and then make sure it's
>> not a
>> class type, and then test if it converts to one integral type.
>
> Then "every integral type" is the weak point -- extensions like long long
> or __int64 are widespread, but their knowledge is tied to compiler/version
> info...
>
> So until official tr1:: support I don;t consider it a stable point, and
> avoid unless very much need some functionality and accept limitation to
> some compilers.
>
I agree with you in principle. But I think we could test after is_enum
signals true (and remove our integral test) whether "T()" converts to
"void*": If it does, it must be an integral type, since T() then is a null
pointer constant. We will have to make sure T is not a floating point type
before.
Then i think the limitation is moved to knowing the three guaranteed
floating point types. (i think i forgot about them in is_enum).
[...]
> Marcel, your solution works perfectly. I like how it
> 'documents' the enum as being a flag set. I'm using this for
> now with a few small additions, but now I'm curious why people
> seem generally opposed to macros...
Because they don't obey scope. In this case, all of the other
solutions have worse problems, so macros are the way to go,
> Anyway, I have a few other small questions if you guys are
> still interested. Balog, you mentioned the ~ operator would
> not be predictable, and it sounds like it's because the way
> enums are stored in memory is not predictable?
No. It's because formally, the results may be a value which is
not in the legal range of the enum (which in your case is
effectively the or of all of the values). In practice, there
won't be any problem, so I wouldn't worry about it (assuming, of
course, that you do convert the value back to the target type).
> This makes me wonder if I should cast to unsigned as in
> Marcel's example, or signed as in Saeed's example and as I was
> doing before. Of course I'll only want to use positive numbers
> for my flag sets, but enums seem to handle negative numbers
> just fine, so I'm not sure what the right thing to do is here.
The safest solution is probably just to use unary + for the
conversion, e.g.:
MyEnum
operator|( MyEnum lhs, MyEnum rhs )
{
return static_cast< MyEnum >( +lhs | +rhs );
}
(The unary + operator is an arithmetic operator, so forces the
conversion of the enum into the underlying type, just as -
would.) If this looks too weird or exotic, there's always
"+ 0" instead.
> So, I guess my question is: is there a way to explicitly store
> an enum as an int, or an unsigned int, or whatever, either
> using a language construct or some kind of compiler
> instrucion? I'm using GCC 4.3.
I have some template metacode somewhere which evaluates the
underlying type, but IIRC, it's a bit hairy. Most of the time,
you don't need variables of the underlying type, however, and
the unary + trick is sufficient.
--
James Kanze
> Thanks for all the great replies!
>
> Marcel, your solution works perfectly. I like how it 'documents' the
> enum as being a flag set. I'm using this for now with a few small
> additions, but now I'm curious why people seem generally opposed to
> macros...
>
> Anyway, I have a few other small questions if you guys are still
> interested. Balog, you mentioned the ~ operator would not be
> predictable, and it sounds like it's because the way enums are stored
> in memory is not predictable?
>
> This makes me wonder if I should cast to unsigned as in Marcel's
> example, or signed as in Saeed's example and as I was doing before. Of
> course I'll only want to use positive numbers for my flag sets, but
> enums seem to handle negative numbers just fine, so I'm not sure what
> the right thing to do is here.
>
> So, I guess my question is: is there a way to explicitly store an enum
> as an int, or an unsigned int, or whatever, either using a language
> construct or some kind of compiler instrucion? I'm using GCC 4.3.
>
This one shows how you can find the right type:
http://stackoverflow.com/questions/1528374/how-can-i-extend-a-lexical-cast-
to-support-enumerated-types/1528436#1528436 . Doing "get_etype<sizeof
find_etype(EnumType())>::type" should give the type that can store all the
enum's values.
That's not the underlying type though - so its sizeof and the one of the
enum may differ, but I think that doesn't matter as long as you can store
all values.
nick wrote:
> Thanks, Balog. I did away with the ~ operator, but instead of
> replacing it with a named function I figured I'd use the - and -=
> operators for unsetting the flag. Here's what I ended up with, maybe
> this will be useful for someone else.
>
> inline static T operator-(T l, T r) \
> { return l&r?(T)((unsigned)l-(unsigned)r):l; } \
I cannot recommend this, since it produces undefined results in case you
try to remove more than one flag at once. Furthermore it creates a
reasonable runtime overhead because of the conditional expression.
I would prefer the use of l&~r, although ~r is not well defined by the
standard so far. In practice there is most likely not even one existing
implementation that breaks this code. And it is very unlikely that one
will ever exist, too, since in C++0x already has defined behavior
because you can specify the underlying type of the enum.
It is much more likely that future versions of the standard address this
kind of use case of enumeration types in some way. This will make the
above code superfluous.
By the way. There is another clean solution without using macros and
undefined behavior. Write your own enumeration class. You could use a
template base class to define the required operators.
template <typename I>
class EnumBase
{protected:
I Value;
EnumBase(I value) : Value(value) {}
};
template <typename I, typename T>
class EnumFlagsBase : EnumBase<I>
{protected:
EnumFlagsBase(I value) : EnumBase(value) {}
friend T operator|(T l, T r)
{ l.Value |= r.Value;
return l;
}
//...
};
class MyEnum : public EnumFlagsBase<unsigned, MyEnum>
{
MyEnum(unsigned value) : EnumFlagsBase(value) {}
public:
static const MyEnum Flag1;
static const MyEnum Flag2;
};
const MyEnum MyEnum::Flag1 = MyEnum(1);
const MyEnum MyEnum::Flag2 = MyEnum(2);
int main()
{ MyEnum val = MyEnum::Flag1|MyEnum::Flag2;
return 0;
}
The resulting object has the memory footprint of the underlying integral
type full type safety and no runtime overhead.
Strictly speaking the not fully specialized base class EnumBase could be
merged into EnumFlagsBase. But if you have some common base functions or
you need enumeration types that are no flags and you do not want the
implicit conversion to int, the additional type might be useful to avoid
unwanted code redundancies in the executable.
Marcel
Ouch, you're right, I don't know what I was thinking here, it should
have been a simple l-=(l&r) ... must have been late. ;)
Now that looks cool, but the problem I have with it is the way the
enums are written... instead of being able to do something like this:
EnumFlagsBase Foobars
{
foo = 1,
bar = 2
}
I have to write:
class Foobars : public EnumFlagsBase<unsigned, Foobars>
{
Foobars(unsigned value) : EnumFlagsBase(value) {}
public:
static const Foobars Foo;
static const Foobars Bar;
};
const Foobars Foobars::Foo = Foobars(1);
const Foobars Foobars::Bar = Foobars(2);
...which seems a bit unwieldy. Thanks for explaining how it would
look, though. I wonder if there's a way to wrangle that into a more
concise format without using macros?
True, but it sounds a little like apples and oranges... preprocessor
directives don't have any concept of scope or anything else in the
code besides other preprocessor stuff. It wouldn't make sense for
macros to obey scope as scope means nothing to them. I guess it would
be nice if you could put a macro inside of a namespace, but I'm not
sure that's realistic?
> > This makes me wonder if I should cast to unsigned as in
> > Marcel's example, or signed as in Saeed's example and as I was
> > doing before. Of course I'll only want to use positive numbers
> > for my flag sets, but enums seem to handle negative numbers
> > just fine, so I'm not sure what the right thing to do is here.
>
> The safest solution is probably just to use unary + for the
> conversion, e.g.:
>
> MyEnum
> operator|( MyEnum lhs, MyEnum rhs )
> {
> return static_cast< MyEnum >( +lhs | +rhs );
> }
>
> (The unary + operator is an arithmetic operator, so forces the
> conversion of the enum into the underlying type, just as -
> would.) If this looks too weird or exotic, there's always
> "+ 0" instead.
>
> > So, I guess my question is: is there a way to explicitly store
> > an enum as an int, or an unsigned int, or whatever, either
> > using a language construct or some kind of compiler
> > instrucion? I'm using GCC 4.3.
>
> I have some template metacode somewhere which evaluates the
> underlying type, but IIRC, it's a bit hairy. Most of the time,
> you don't need variables of the underlying type, however, and
> the unary + trick is sufficient.
>
> --
> James Kanze
That + trick is great, it actually makes a lot of sense and doesn't
seem weird at all. In light of your comments and Marcels', I've
revised the macro again...
#define FLAGS_(T) \
inline static T operator * (bool l, T r) \
{ return static_cast<T>(l*+r); } \
inline static T operator * (T l, bool r) \
{ return static_cast<T>(+l*r); } \
inline static T operator | (T l, T r) \
{ return static_cast<T>(+l|r); } \
inline static T operator & (T l, T r) \
{ return static_cast<T>(+l&r); } \
inline static T operator + (T l, T r) \
{ return l|r; } \
inline static T operator - (T l, T r) \
{ return static_cast<T>(+l-(l&r)); } \
inline static T& operator |= (T& l, T r) \
{ return l = l|r; } \
inline static T& operator &= (T& l, T r) \
{ return l = l&r; } \
inline static T& operator += (T& l, T r) \
{ return l = l+r; } \
inline static T& operator -= (T& l, T r) \
{ return l = l-r; }
...I'm pretty happy with it. Thanks for the help!
[...]
> I would prefer the use of l&~r, although ~r is not well
> defined by the standard so far.
The expression ~r is perfectly well defined by the standard, and
poses no problem. The problem with ~r only comes if you try to
convert the results back into the original enum type (and even
then, only in theory). If both l and r are valid values to
begin with, however, the results of l&~r can be safely converted
back to the original type.
--
James Kanze