6

When comparing enums that come from different sources such as those of the following code GCC emits warnings. Is there a way to avoid these warnings without c-style casts?

struct Enumerator
{
    enum { VALUE = 5 };
};

template<int V>
struct TemplatedEnumerator
{
    enum { VALUE = V };
};

if(Enumerator::VALUE == TemplatedEnumerator<5>::VALUE)
{
  ...
}

And GCC emits the following type of warning:

GCC: warning: comparison between 'enum ...' and 'enum ...'
Robert Gould
  • 68,773
  • 61
  • 187
  • 272
  • I believe you're going to be stuck with casts. – OJ. Jan 28 '09 at 05:28
  • struct Enumerator : boost::integral_constant {}; or even struct Enumerator : mpl::int_<4> {}; better than enums imho. c++1x will also have integral_constant => you're future safe. and you can then just compare ::value of different types. – Johannes Schaub - litb Jan 28 '09 at 10:09
  • Unfortunately because of the policies of the project boost is off limit :( – Robert Gould Jan 28 '09 at 15:54

6 Answers6

9

I believe you can provide your own comparison operators, but you'll have to name the enums first:

struct Enumerator
{
    enum Values { VALUE = 5 };
};

template<int V>
struct TemplatedEnumerator
{
    enum Values { VALUE = V };
};


template <int V>
bool operator==(Enumerator::Values lhs, typename TemplatedEnumerator<V>::Values rhs)
{
    return static_cast<int>(lhs) == static_cast<int>(rhs);
}

template <int V>
bool operator==(typename TemplatedEnumerator<V>::Values rhs, Enumerator::Values lhs)
{
    return static_cast<int>(lhs) == static_cast<int>(rhs);
}

Interestingly Visual Studio doesn't actually warn about comparing the two enumerator types, but rather warns about a constant value in a if statement - just like it will if you do this:

if (true) {...}
Eclipse
  • 44,851
  • 20
  • 112
  • 171
  • I'd be very hesitant about doing this. Comparing enums of different kinds shouldn't be something that "just works". While there is occasionally a need for it I believe making it explicit in the code is preferable. You can still wrap it in a helper function, but overloading operators seems wrong. – philsquared Jan 28 '09 at 07:25
  • If these enums exist only for the purpose of comparing them (common in template metaprogramming), then allowing them to be compared seems like a reasonable thing to do. Note that these operators will not affect the behavior of any other enums. – Eclipse Jan 28 '09 at 16:04
  • Thanks for your help Josh, but Konrad Rudolph's solution seems to be more updated, hadn't realized that would actually work, but your assumptions were all right. – Robert Gould Jan 29 '09 at 05:49
2

If there are N enums, won't there need to be N * (N - 1) comparison operators? That could end up being a lot.

Couldn't you just use the implicit conversion of enums to ints and do:

bool equals(int lhs, int rhs)
{
  return lhs == rhs;
}

Then you can just do this in your code:

if(equals(Enumerator::VALUE, TemplatedEnumerator<5>::VALUE))
{
  ...
}

Also, you can check out enum-int casting: operator or function. The accepted answer says that you shouldn't use the implicit conversion, but a correctly named function like equals should make the code very readable and maintainable.

Community
  • 1
  • 1
ZaDDaZ
  • 131
  • 5
  • you're right about the amount of code, but with full optimization they will all melt away, so there won't be as much overhead – Robert Gould Jan 28 '09 at 06:10
  • "If there are N enums" - then I would consider it a code smell. Even when N==1 I would check the design first - but these things to become necessary from time to time. The rest of your solution is ok - but "equals" might be too generic a name for this. What about "CompareDifferentEnums"? – philsquared Jan 28 '09 at 07:27
  • I agree with the necessity question. I assumed that was already considered when asking the question however and hopefully offered the easiest solution. I am not sure about the name though, this function would compary any to ints, not just enums. – ZaDDaZ Jan 28 '09 at 14:33
2

Don't do it.

The warning is there because you shouldn't mix up different enums in the first place.

For constants you can use a const declaration.

starblue
  • 55,348
  • 14
  • 97
  • 151
1
#include <iostream>
using namespace std;

struct Enumerator 
{
  enum {value = 5 };
};


template<int v>
struct TemplatedEnumerator
{ 
  enum {value = v};
};



int main(void)
{
  if (static_cast<int>(Enumerator::value) ==
    static_cast<int>(TemplatedEnumerator<5>::value))
    cout << "Yoh\n";
}
Friedrich
  • 5,916
  • 25
  • 45
1

Simple answer in your case: don't use an enum, use an inline-defined static const int:

struct Enumerator
{
    static int const VALUE = 5;
};

template<int V>
struct TemplatedEnumerator
{
    static int const VALUE = V;
};

In this special case, that's equivalent and all compilers of the last few years should treat it so (I know for a fact that all the major ones do).

See also: static const Member Value vs. Member enum : Which Method is Better & Why?

Community
  • 1
  • 1
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • will need to check it out, maybe this will work, but these enumerators are doing some very serious work so I can't say yet – Robert Gould Jan 29 '09 at 03:32
  • Tried the replacement and it worked, thanks! I had been carrying the enum hack in my bag of tricks from the days when most compilers didn't get the static const thing right! – Robert Gould Jan 29 '09 at 05:47
0

You're missing the obvious answer. No, don't use c-style cast. Use C++-style casts:

if(static_cast<int>(Enumerator::VALUE) == static_cast<int>(TemplatedEnumerator<5>::VALUE))
{

}

Perfectly safe, perfectly acceptable. Two enums are not the same types, so if there's anything fishy in your code, it's not the cast, it's the attempt to compare two distinct types. But as long as you do it, a cast would be my preferred way to do it. Yes, you could define a comparison operator, but a cast makes it clear that you're comparing two technically unrelated types.

jalf
  • 243,077
  • 51
  • 345
  • 550