c++ enum can compare to integer but not assign from integer? - c++

#include <iostream>
enum mode { MODE0=0, MODE1, NUM_MODES};
int main(int args, char ** argv) {
int i = 1;
std::cout << (i == MODE0 ? "true" : "false") << "\n";
std::cout << (i == MODE1 ? "true" : "false") << "\n";
mode test;
test = i; // error
}
Why is it that the comparison of i to enum values works fine, but I get compilation error when assigning mode test variable to an integer value?
enum.cc:10:8: error: invalid conversion from 'int' to 'mode'
[-fpermissive]
My question is specifically about why comparison works and assignment doesn't (not how to fix my code) and it has received a couple of good explanations below.

MODE0, MODE1 and NUM_MODES are guaranteed to be convertible to int (the underlying type of the enum) but the reverse is not true. Not all int can be converted to mode. For example, what is the matching mode for the int 42? Simply put, only the implicit conversion from enum to int is defined, the opposite implicit conversion is not defined.
If you want to convert from int to mode you can preform a static_cast to signal that you are taking the responsibility of ensuring that the value being converted is always legal to convert to mode. Try
test = static_cast<mode>(i);
You can use strongly typed enumerations by adding the class keyword to your enum to prevent any implicit casts and to limit the scope of the enum value names. The definition would look like enum class mode { MODE0 = 0, MODE1, NUM_MODES };. In this case, you must quality the enum value names, for example, you would need to use mode::MODE0 instead of MODE0. This has the advantage that it avoids name collisions.

It's because there is a conversion from an enumerated type to int but there is no conversion in the opposite direction. For the comparison, MODE0 gets promoted to int. For the assignment, i would have to be converted to mode.

Look at it this way. When you do a comparison it doesn't matter if the int is not a valid possible value. If it is not then the comparison will fail and we can go on. Now when we go and try to assign an int to an enum you could assign to it a value that isn't mapped to the enum values. Since we don't want this implicitly happening the conversion is invalid. If you want to tell the compiler that it is okay, you know what you are doing, then you can cast it like:
test = static_cast<mode>(i);

Related

Is printing of a member pointer to an int defined

Suppose I have this code:
#include <iostream>
struct Mine
{
int a;
int b;
};
int main()
{
int Mine::* memberPointerA = &Mine::a;
int Mine::* memberPointerB = &Mine::b;
std::cout << memberPointerA;
std::cout << "\n";
std::cout << memberPointerB;
}
When I run this with Microsoft Visual C++ (2015)
I get the following output
1
1
The output I expect is something more like this:
1
2
So this begs the question: Is this printing of a member pointer defined behavior?
There's a defined conversion from pointer to bool. Since the member variable pointers are not NULL, they evaluate as true and print as 1.
The key issue at hand is that a pointer-to-member cannot be converted to void*, which is what the overload that usually handles printing pointers takes.
Thus, the next best conversion is used, which is the conversion pointer->bool. Both pointers are not null pointers, thus you get the output you see.
If you try printing "normal" pointers (as opposed to pointers to member), you would get the some output along the lines of what you expected initially.

why int a= 4i; not report an syntax error(c++)

#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
int a = 232u;
int b = 4i;
cout << a << endl << b;
}
I was review basic of cpp, As the screen shot I took, I tried to sign an unsigned int to a int which was fine, then I tried change that u to i and waiting for a error, but there's no error and output was 0. There's no define of i. So what happened.
I'm using xcode on mac, last picture is the build settings.
C++ has a concept of literals, this is used to describe the type of a value. For example, integer literal can be used to write I want a integer 1 with a type unsigned int. We will write it 1u.
In your case, your are probably using a GNU extension for imaginary constants. What you write don't compile in C++ standard.
The good way to use complex literal in C++ standard is to include include <complex>. And to use std::complex_literals, this is only possible in C++14.
The suffix i denotes the imaginary part of a complex number; when assigning an (implicitly) constructed complex number to integral value, only the real part is taken.
Hence, the following expression yields 0:
int b = 4i; // gives 0; real-part of 4i is 0, imaginary-part is 4: casting to int gives the real part, i.e. 0
But:
int x = 4i*4i; // gives -16; as i means the square root of -1, i*i yields -1; so 4i*4i = -16
Note that this works even without including <complex>.

Conversion Enum to Boolean type

In my application i want to represent AND as 1 , and OR as 0, instead of opting for #define method , i am using enum to represent them , as shown in the below example program
#include <stdio.h>
enum gateConnection_t
{AND,OR}
gateConnection;
int main()
{
bool and_t = AND;
bool or_t = OR;
printf("%d\n",and_t);
printf("%d\n",or_t);
return 0;
}
As seen above , i am directly assigning the enum values to boolean vvariables. The program works as expected and my only question is whether the internal cast done is safe , or is it better to use explicit casting such as static_cast ?
For starters, your {AND,OR} are the wrong way round.
Enums by standard start at 0 (although you can override that).
Use
enum gateConnection_t
{OR,AND}
instead.
The cast is safe by the way.
Conceptually though it's a nasty thing to do. Why do you want this; particularly in C++? What's wrong with true and false?
enum gateConnection_t
{AND=1,OR=0}
gateConnection;
or
enum gateConnection_t
{
OR=0,
AND //<== this equal to the previous plus one automatically
}gateConnection;

Changing data size of enumerated types C++

By default enumerated type variables take the size of integer i.e 4 bytes in memory. Is there any way to convert this to any other data type size.
Am not talking about type casting, but the memory size required to store an enumerated type.I have referred this question But it didn't tell about changing the integer size to any other.Any help.
c++11 introduced strongly typed enums (and Strongly Typed Enums (Revision 3)), which permits the specification of the underlying integral type:
#include <iostream>
enum E_ushort : unsigned short { EUS_1, EUS_2 };
enum E_ulong : unsigned long { EUL_1, EUL_2 };
int main()
{
std::cout << sizeof(E_ushort::EUS_1) << "\n";
std::cout << sizeof(E_ulong::EUL_1) << "\n";
return 0;
}
Output:
2
4
by reading some documentation on this website i think it's not possible. In fact it's logical. An enum list just a list with item's referenced by numbers. So, first question which type or you looking at? do you need an enum list who the nomber of item's are to bing for a int ? Or, are you looking at an other type like float char long.. in this case i don't think it's possible

Why can't I increment a variable of an enumerated type?

I have a enumerated type StackID, and I am using the enumeration to refer to an index of a particular vector and it makes my code easier to read.
However, I now have the need to create a variable called nextAvail of type StackID. (it actually refers to a particular stackID ). I tried to increment it but in C++, the following is illegal:
nextAvail++;
Which sort of makes sense to me ... because there's no bounds checking.
I'm probably overlooking something obvious, but what's a good substitute?
I also want to link to this question.
I'm probably overlooking something obvious, but what's a good substitute?
Overloading operator++:
// Beware, brain-compiled code ahead!
StackID& operator++(StackID& stackID)
{
#if MY_ENUMS_ARE_CONTIGUOUS && I_DO_NOT_WORRY_ABOUT_OVERFLOW
return stackID = static_cast<StackID>( ++static_cast<int>(stackID) );
#else
switch(stackID) {
case value1 : return stackID = value2;
case value2 : return stackID = value3;
...
case valueN : return stackID = value1;
}
assert(false);
return stackID; // some compilers might warn otherwise
#endif
}
StackID operator++(StackID& stackID, int)
{
StackID tmp(stackID);
++stackID;
return tmp;
}
Because enumerations do not have to be contiguous. E.g. take this example:
enum Colors {
cRed, // = 0
cBlue, // = 1
cGreen = 3
}
What should happen in this scenario?
Colors color = cBlue;
Colors other = color++;
Should other be cGreen or should it be 2. In that case it's not a valid enumeration member anymore. What about this?
Colors color = cGreen;
Colors other = color++;
Should other be cRed (wrap around) or 4?
As you can see, being able to increment enumeration values introduces a whole lot of questions and complicates the simple mechanism that they intend to be.
If all you care about is the integer value being incremented, then simply cast to int and increment that.
Casting back and forth to/from int is of course the obvious solution, then you make clear that you understand that the addition is happening "outside" the enum:
nextAvail = static_cast<StackID>(static_cast<int>(nextAvail) + 1);
Why not store nextAvail as an int instead if you're going to do arithmetic operations on it?
Another option would be to wrap the enum in your own type and overload operator ++ for it (which also could wrap around or something for instance).
An enumeration is semantically supposed to represent a set of distinct related, values.
So you could have
enum Colour {RED, GREEN, BLUE};
But that should be equivalent to:
enum Colour {GREEN, BLUE, RED};
The problem is that if you increment an enum then those representations are not the same. GREEN++ in the first case is not the same as GREEN++ in the second.
Making your program dependent on the declaration of the enum is a recipe for disaster - maintainers may assume that the order of the enum doesnt matter, introducing many silent bugs.
Very Simple:
nextAvail = (StackID)(nextAvail + 1);
Enums are going to be type int, so you can cast them. Is this what you're trying to do?
int ndx = (int) StackID.SomeValue;
...
++ndx;
This is going to make someone very confused down the line, of course.
It occurs to me that you're using an enum where you should be using const, or even #define. enum is most appropriate when you have arbitrary values (where the exact value is not meaningful).
I've overloaded the ++/-- operator in this way:
enum STATE {STATE_1, STATE_2, STATE_3, STATE_4, STATE_5, STATE_6};
// Overload the STATE++ operator
inline STATE& operator++(STATE& state, int) {
const int i = static_cast<int>(state)+1;
state = static_cast<STATE>((i) % 6);
return state;
}
// Overload the STATE-- operator
inline STATE& operator--(STATE& type, int) {
const int i = static_cast<int>(type)-1;
if (i < 0) {
type = static_cast<STATE>(6);
} else {
type = static_cast<STATE>((i) % 6);
}
return type;
}
With respect to oprator++, $5.2.6/1 states- "The type of the operand shall be an arithmetic type or a pointer to a complete object type."
StackID does not fit the bill here. It is of enumeration type.
One option is like this
$5.7/1 - "For addition, either both operands shall have arithmetic or enumeration type, or one operand shall be a pointer to a completely defined object type and the other shall have integral or enumeration type."
enum Possibility {Yes, No, Maybe};
Possibility operator++(Possibility const& r){
return Possibility(r + 1); // convert r to integer, add 1, convert back to Enum
}
int main(){
Possibility p = Yes;
Possibility p1 = ++p;
}
I'm quite happy with this C plus C++ solution for a for loop incrementing an enum.
for (Dwg_Version_Type v = R_INVALID; v <= R_AFTER; v++)
=>
int vi;
for (Dwg_Version_Type v = R_INVALID;
v <= R_AFTER;
vi = (int)v, vi++, v = (Dwg_Version_Type)vi)
The other solutions here are not C backcompat, and quite large.