tags:

views:

342

answers:

3

I have the following code snippet:

enum { one } x;
enum { two } y;
x = y;

That will compile in C, but in C++, I get the following error:

test.c:6: error: cannot convert ‘main()::<anonymous enum>’ to ‘main()::<anonymous enum>’ in assignment

Can someone explain to me why this is happening? I would prefer an answer with some specifics about why the compiler behaves this way, rather than just "You can't do that"

+19  A: 

Converting from one enum type to another goes via an integer type (probably the underlying type of the source, not sure).

An implicit conversion from enum to an integer type is allowed in both C and C++. An implicit conversion from an integer type to enum is allowed in C, but not in C++.

Basically, C++ is being more type safe. It's trying to stop you doing this:

enum {zero, one, two} x;

x = 143; // assigns a value outside the range of the enum

If you want to perform this enum-enum conversion in C++, you could use typeof/declspec/boost typeof or equivalent. In GCC:

int main() {
    enum {zero, one, two} x;
    enum {zero1, one1, two1} y = two1;
    typedef typeof(x) xtype;
    x = static_cast<typeof(x)>(y);
}

It doesn't normally make sense to do so, though. For most purposes, enums (and especially anonymous ones) are "enumerated types". They do just happen to be "implemented" by the C and C++ standards as integers wearing funny hats, but that doesn't mean that red is "equal to" hammer just because they each appear first in two different enums (colours and tools respectively). static_cast suggests that there's a relation between the two types involved. Any two enum types are "related" by the fact that both have an underlying integer type, and those are related, so the "relation" there really doesn't say much. If you write this code you're getting a pretty poor version of type safety.

Steve Jessop
You've got a whole bunch of points from this, so why not check and mention whether Boost TYPEOF (or some other means) is capable of constructing the cast expression that would be necessary to assign any foreign type to an anonymous enum variable… (edit - I don't have Boost installed, scandalous!, or I'd try.)
Potatoswatter
Fair enough. Not sure why you'd want to do it, though, if you want to treat an enum like an integer, don't use an anonymous enum :-) I'm stuck on an old version of boost, doesn't have typeof, but I tried it on g++ and it seems happy to take an anonymous type. I haven't checked whether `decltype` will do the same.
Steve Jessop
The only reason I have ever seen for the need was for serialization. The enum being serialized as integer type and deserialized first in an integer type and then an enum... I've always found it awkward, especially because the writer had used an unsigned integer type...
Matthieu M.
You could create a class with a conversion function in it. A object generator like `template<typename EnumType> caster<EnumType> make_caster(EnumType e) { return caster<EnumType>(e); }` could then be used like `x = make_caster(y);` (incidentally, C++03 does not support unnamed types as template arguments, so you still need to hope for compiler-help tho).
Johannes Schaub - litb
+1  A: 

My guess is that this is due to the stricter typing in C++.

In C x = 5; also compiles. In C++ it won't because there is no type conversion defined. That's the same reason why x = y does not compile.

You can have a look at this example on codepad, which gives a more detailed error description than your compiler.

mxp
A: 

The compiler does not know how to implicitly convert one enumerated data type to another.

Try the following.

enum typeX { one } x;
enum typeY { two } y;
x = (typeX) y;
semaj
I'm primarily concerned with anonymous enums, not named ones.
samoz
@samoz - The answer is the same regardless of whether the enums are named or not. You have created two new data types an the compiler does not know how to implicitly convert one to another, thus the error.
semaj