tags:

views:

251

answers:

5

Is there a way to make enum type to be unsigned? The following code gives me a warning about signed/unsigned comparison.

enum EEE {
    X1 = 1
};

int main()
{
    size_t x = 2;
    EEE t = X1;
    if ( t < x ) std::cout << "ok" << std::endl;

    return 0;
}

I've tried to force compiler to use unsigned underlying type for enum with the following:

enum EEE {
    X1 = 1,
    XN = 18446744073709551615LL
    // I've tried XN = UINT_MAX (in Visual Studio). Same warning.
};

But that still gives the warning.


Changing constant to UINT_MAX makes it working in GNU C++ as should be according to the standard. Seems to be a bug in VS. Thanks to James for hint.

A: 

According to http://stackoverflow.com/questions/159034/are-c-enums-signed-or-unsigned your compiler gets to choose whether enum is signed or not, though there are some comments saying that in C++0x you will be able to specify that it is unsigned.

mathmike
+2  A: 

Not in the current version of C++. C++0x will provide strongly typed enums.

For the time being, you can use if ( static_cast<size_t>(t) < x ) to remove the warning.

In silico
I'm trying to avoid extra `static_cast`'s.
Kirill V. Lyadvinsky
+6  A: 

You might try:

enum EEE {
    X1 = 1,
    XN = -1ULL
};

Without the U, the integer literal is signed.

(This of course assumes your implementation supports long long; I assume it does since the original question uses LL; otherwise, you can use UL for a long).

James McNellis
This works in GNU C++, but not in Visual Studio. Seems to be a bug in VS. This code is correct also, but better to use `UINT_MAX`.
Kirill V. Lyadvinsky
@James, Ah, indeed. If you do it with "LLU" instead of just with "U" like i did, it can't choose "long" anymore. Good way to get around the unclear wording of what "larger" means! I would upvote if you use a limit macro or `-1ULL` (or `-1UL` in C++03 or long long implementation) :)
Johannes Schaub - litb
`ULLONG_MAX` doesn't work in VC++ also. I think compiler thinks he can generate 128bit code.
Kirill V. Lyadvinsky
@Johannes: Thanks for reminding me about the -1 trick; it had slipped my mind.
James McNellis
@Kirill: No matter what value I give an enumerator, the enumeration always has a size of four bytes in VS2008. :-/
James McNellis
A: 

Why not

enum EEE {
    X1 = 1,
    x = 2 // pick more descriptive name, a'course
};

or

if ( size_t( t ) < x )
Potatoswatter
How do you know that your enum values for the enum EEE are unsigned? They look like ints to me.
chollida
@chollida, the ultimate goal was to get rid of the warning, not to make it unsigned, i would suspect. His way does achieve that.
Johannes Schaub - litb
@cohollida: the question is how to make the enum type unsigned. That would imply he won't put negative values in, or he wants modulo arithmetic if he does.
Potatoswatter
+3  A: 

You could also overload the operators if you want to compare it

enum EEE {
    X1 = 1
};

bool operator<(EEE e, std::size_t u) {
  return (int)e < (int)u;
}

However you have to do that dance for any integer type on the right side. Otherwise if you do e < 2 it would be ambiguous: The compiler could use your operator< matching the left side exactly but needing a conversion on the right side, or its built-in operator, needing a promotion for the left side and matching the rigth side exactly.

So ultimately, i would put the following versions:

/* everything "shorter" than "int" uses either int or unsigned */
bool operator<(EEE e, int u) {
  return (int)e < (int)u;
}

bool operator<(EEE e, unsigned u) {
  return (unsigned int)e < (unsigned int)u;
}


bool operator<(EEE e, long u) {
  return (long)e < (long)u;
}

bool operator<(EEE e, unsigned long u) {
  return (unsigned long)e < (unsigned long)u;
}

/* long long if your compiler has it, too */

Not very nice :) But at least the user of your enumeration has easy going. However if you ultimately don't want to compare against ordinary int but against some meaningful value, i would do what some other guy proposed, and add another enumerator that has as value 2, and name it. That way, warnings will go away too.

Johannes Schaub - litb
Rather verbose, but gets the job done if you are looking to avoid static_cast
Ramon Zarazua
`-1U`? are you trying to apply an unary minus operator to unsigned type? Should that change the type to signed?
Kirill V. Lyadvinsky
@Kirill, it will stay `unsigned` but will change its value to `UINT_MAX`. So you don't need the limits header.
Johannes Schaub - litb
I removed the "trick" with the `UINT_MAX` because i think "larger" means actually the "sizeof" value - as in "size of the type" (after asking dgregor). "long" could be the same size of "unsigned int" and so it could choose still "long". The only safe way seems to be to use @James solution and use `-1ULL` if you wanna stay with the enum without casts and operator overloading and stuffs.
Johannes Schaub - litb
`-1ULL` looks promising, but in Visual Studio it doesn't work either. I'll try to post bug in VS bug tracker.
Kirill V. Lyadvinsky
Of course you would then need to implement all the other comparisons operator (boost.operators might help)... could you get away with a template using `boost::enable_if` and `boost::is_signed` / `boost::is_unsigned` (or perhaps just `boost::is_integral`) ?
Matthieu M.
@Matthieu yeah i suspect we could get away with a template like that.
Johannes Schaub - litb