3

C++ is mostly a superset of C, but not always. In particular, while enumeration values in both C and C++ implicitly convert into int, the reverse isn't true: only in C do ints convert back into enumeration values. Thus, bitflags defined via enumeration declarations don't work correctly. Hence, this is OK in C, but not in C++:

typedef enum Foo { Foo_First = 1<<0, Foo_Second = 1<<1, } Foo; int main(void) { Foo x = Foo_First | Foo_Second; // error in C++ return 0; } 

How should this problem be handled efficiently and correctly, ideally without harming the debugger-friendly nature of using Foo as the variable type (it decomposes into the component bitflags in watches etc.)?

Consider also that there may be hundreds of such flag enumerations, and many thousands of use-points. Ideally some kind of efficient operator overloading would do the trick, but it really ought to be efficient; the application I have in mind is compute-bound and has a reputation of being fast.

Clarification: I'm translating a large (>300K) C program into C++, so I'm looking for an efficient translation in both run-time and developer-time. Simply inserting casts in all the appropriate locations could take weeks.

3 Answers 3

9

Why not just cast the result back to a Foo?

Foo x = Foo(Foo_First | Foo_Second); 

EDIT: I didn't understand the scope of your problem when I first answered this question. The above will work for doing a few spot fixes. For what you want to do, you will need to define a | operator that takes 2 Foo arguments and returns a Foo:

Foo operator|(Foo a, Foo b) { return Foo(int(a) | int(b)); } 

The int casts are there to prevent undesired recursion.

Sign up to request clarification or add additional context in comments.

6 Comments

Going through hundreds of thousands of lines of source code inserting casts is not my idea of an efficient translation.
@Ferruccio, wouldn't the syntax be "Foo x = (Foo)(Foo_First | Foo_Second);"
You can do that too. I used a C++ style cast. C style casts still work.
If you have a Foo operator|(Foo, Foo), why would you need to cast (Foo_First | Foo_Second) ?
You don't. I was describing two different solutions. You either cast each instance to a Foo or you implement operator| for Foos. You don't need to do both.
|
2

It sounds like an ideal application for a cast - it's up to you to tell the compiler that yes, you DO mean to instantiate a Foo with a random integer.

Of course, technically speaking, Foo_First | Foo_Second isn't a valid value for a Foo.

3 Comments

in this case, it is - 1|0 is still 1
The idiom is valid in C, and I am trying to translate a large (>300K) C program into C++, so I'm looking for an efficient translation in both run-time and developer-time.
@warren - 1<<0 == 1, 1<<1 == 2; it is not 1|0, but 1|2 == 3.
0

Either leave the result as an int or static_cast:

Foo x = static_cast<Foo>(Foo_First | Foo_Second); // not an error in C++ 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.