Since the C++11 transition GCC outputs a warning "enumeral and non-enumeral type in conditional expression". I'd like to understand the reasoning behind this warning. What are the perils of comparing enum constants?
It is obvious we can get rid of this warning by
-Wno-enum-compare
But why the hassle? Personally, I always strive at writing warning free code, and usually the warnings emitted by default are quite sensible. For example, it figures that it's dangerous to compare signed and unsigned integers.
But using enums is widely used idiomatic C++ metaprogramming. I am not aware of any alternative, which is similarly readable, concise and to the point and does not require any actual storage.
To quote a concrete example: What can go wrong with the following metafunction, so that a warning would be adequate?
template<class TYPES>
struct MaxSize;
template<>
struct MaxSize<NullType>
{
enum{ value = 0 };
};
template<class TY, class TYPES>
struct MaxSize<Node<TY,TYPES> >
{
enum{ thisval = sizeof(TY)
, nextval = MaxSize<TYPES>::value
, value = nextval > thisval? nextval:thisval
};
};
It looks like an issue in GCC. This doesn't depend on -std=c++11
option. The warning is related not to comparison, but to the conditional operator.
Seems that the warning is issued only if one of enum members is iniatialized with an unsigned value, and another one is initialized with the value of another enum. Also, the warning is issued only in the initialization of enum members.
I managed to strip down the code to the following:
enum A { valueA = 1 };
enum B {
// if you change 0u to 0, there'll be no warning
thisval = 0u,
// if you change valueA to any integral constant, there'll be no warning
nextval = valueA,
// warning on this line
value = nextval > thisval ? nextval : thisval,
// no warning here
value2 = nextval > thisval
};
int main() {
// no warning here
(void)(nextval > thisval ? nextval : thisval);
// the same warning also here - but not with Clang
(void)(nextval > thisval ? nextval : false);
}
Online demo
Clang doesn't issue any warnings on this code (except that with -Weverything
it complains about unreachable code), though it could really say something on the last line.
(GCC 4.9.2, Clang 3.5.0)
If you are using the enum as a way to define a compile time constant value , you can stop doing that now.
Use this instead:
constexpr int myConstant = 123;
where int
can be anything that qualifies as a literal type
[I won't try to define literal type here -- it's complicated and Google is your friend.]
Alternatively even before c++11 you could say:
class Foo{
static const int myConstant = 123;
};
where int can be any integral type.
There is no need to have the corresponding definition in a cpp file unless you need the address of myConstant somewhere.
The compiler is telling you that comparing an enum value to anything other than another value in the same enumeration is fragile code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With