Home
Wednesday, August 23, 2017
10:20:11 AM
Users online: 0   You are here >> Home > Programming

Forums | Programming Forums search
Forum FAQ
   
  1  
What's this about a new C++ standard for enums?
Meeko 
7/8/08 9:57:23 PM
Titan

I hear that there are C++ standards out there - perhaps a change I haven't caught up with - where we cannot use enums as a value. So we have to refer to the enum values specifically by their names, and cannot perform operations on them. Or something. I read about it ages ago and haven't really looked it since, so now that I'm looking at buying some new software development packages I'm not sure how I can cope with the changes. Can anybody remember what the changes to enums were?

It strikes me that might make it more difficult to program, as I'll show below.

For example, I have:

enum MyEnum { 
ZERO,
ONE,
TWO
};


And later I declare an array:

 
MyEnum pMyArray[TWO];
int j = 0;
for(MyEnum i = ZERO; i < TWO; i++)
pMyArray = j++;


Or do something like:

 
int i;
i = foo(); // Returns, say, i = 1.
int k = pMyArray[ZERO + i];


Which of these are legal/illegal under the new standard and why?

-----

kikz 
7/8/08 10:47:59 PM
Immortal

semantically, enums aren't constants. If you're going to have type safety you can't treat them as such either.

-----
Q6600 | 4Gb PC6400 | 2 x 500Gb RAID 0 + 2 x 320 Gb RAID 0 | 19" Benq FP591 + 24" Samsung 245B + 19" Dell | 8800GTS 640 Mb + 8400GS 256 Mb | Gigabyte GA-P35-DS3P | Antec P182 | Corsair HX-620 | Thermalright 120 Extreme | Vista x64

Meeko 
7/8/08 11:01:55 PM
Titan

I was afraid of that. But not all compilers are strict on this, are that? That is, is it worth my while asking them what their take on this is, or should I not bother?

It's annoying, though, because what else am I supposed to do? I have been relying on it for this purpose:

enum MyEnum { 
BLAH,
MORE_BLAH,
SOME_MORE_BLAH,
BLAH_CNT
}

// ...

int MyArray[BLAH_CNT];



With the idea of having an array that EXACTLY stores all the relevant enums and I can keep track of all their properties in there.

For example, say I'm designing a game, I use:

 
enum Weapons {
WEAP_SWORD,
WEAP_BOW,
WEAP_HAMMER,
WEAP_TEETH,
WEAP_CNT
}


And later, in the character class, I have an array representing their inventory:

 
unsigned long mWeapons[WEAP_CNT];


And then access the number of each weapon they're carrying with them with the member:

 
unsigned long Player::NumWeapons(Weapons weaponName)
{
return mWeapons[weaponName];
}


This allows me to add or subtract more weapons to the list quite easily. Without this shortcut it seems like it would be quite a hassle to set this sort of system back up. :-

Mind you, I am a bit fuzzy on this since I haven't touched C++ for a while, but this is how I remember it. And I would admit to being only a mediocre coder at best, so I'm probably missing a much easier way of doing things that fits with the standard.

-----

kikz 
7/8/08 11:37:58 PM
Immortal

I don't see what's wrong with using constants if that's what you're trying to achieve. You shouldn't be using enum's in C++ for this purpose. In C, enums and ints are interchangeable, but in C++ they're a specific type (like in C#, where you can cast to an int, or call Enum.Parse(typeof(Weapons), 1) to back the other way.

-----
Q6600 | 4Gb PC6400 | 2 x 500Gb RAID 0 + 2 x 320 Gb RAID 0 | 19" Benq FP591 + 24" Samsung 245B + 19" Dell | 8800GTS 640 Mb + 8400GS 256 Mb | Gigabyte GA-P35-DS3P | Antec P182 | Corsair HX-620 | Thermalright 120 Extreme | Vista x64

Meeko 
8/8/08 7:52:57 AM
Titan

The reason I have been using it this way, kikz, is because it allows me to create arrays of the perfect size effortlessly - without having to worry about when I add or subtract items from the enum.

For example, in the future I might want to add WEAP_GUN to the list, and by using WEAP_CNT to initialise the array and WEAP_BOW to access a particular element in the array table, it's a lot easier to code and understand.

The alternative is to use #define WEAP_BOW 5, say, to allow me to use WEAP_BOW to access that specific element of the array - but if I add or subtract weapons from the list, I would have to go and find all the places where I initialised the arrays and change the number of elements whereas this way, with enums, WEAP_CNT is automatically always the correct value. I guess it's just one extra step, using #define WEAP_CNT and changing its value, but I have been using the enums for other safety things I will have to think about.

Is there a quick and efficient way to do what I am doing in C++ without using enums incorrectly like I have? Is the #define method or use of global constants the only real alternative? I have always used enums and it seems a hassle to change the code.

-----

kikz 
8/8/08 9:32:15 AM
Immortal

heh, so you have WEAP_CNT as the last enumeration so you'll know the number of weapons you have. So really, not only are you using enumerations in the wrong place, you're using then incorrectly :p WEAP_CNT should be a possible value of weapons, not the maximum number of weapons. Enums basically define the possible values in a domain.

I get why your doing it, but it's just wrong :p

using #define isn't the way to go either, because all it's doing is text replacement before compilation. Use integer constants.

The class constructor initializes the array. That way the initialization only occurs in one place. Isn't the weapons array being initialized in the Player constructor now? That should only be a change in one place.

What happens if I take over maintenance of your code and call the following:
 
unsighed long count = player->NumWeapons(WEAP_CNT);

It woudl seem valid to me, because WEAP_CNT is just another weapon...


Face it, what you're doing is using the langauge not as it was intented, and that's just asking for trouble :)

-----
Q6600 | 4Gb PC6400 | 2 x 500Gb RAID 0 + 2 x 320 Gb RAID 0 | 19" Benq FP591 + 24" Samsung 245B + 19" Dell | 8800GTS 640 Mb + 8400GS 256 Mb | Gigabyte GA-P35-DS3P | Antec P182 | Corsair HX-620 | Thermalright 120 Extreme | Vista x64

Meeko 
8/8/08 8:04:04 PM
Titan

What do you mean WEAP_CNT should be possible value instead of maximum number, kikz? I initialise an array with WEAP_CNT elements - enough to store all values for the enums. Then each element in the array stores the number of each particular weapon being carried. So mWeapons[WEAP_BOW] = 5; means they're carrying 5 bows.

I am using the enums in header files that are shared among different classes that do different things with their weapons. There might be one lying on the ground, for example, and that's in the Ground class.

And I put in code to handle calls to WEAP_CNT.



Integer constants might be all right, but I think in practice it has similar flaws as defines compared to enums. For example:

1) If I remove a weapon from the list, I would have to change the value for WEAP_CNT and some other weapons. I have the choice between changing them all down one, or just changing the second-highest value (so if WEAP_CNT was originally 35, I change it to 34 and look for WEAP_BLAH = 35 and change that to the value I deleted). But that could get messy. It doesn't seem too bad, though...but enums do it automatically.

2) Type handling. I can create Weapon mName as a member, say, to make it easier to identify what the object is later on. This is useful for keeping track of inventory. For example, I create an Item class and a Weapon child class. I then create an "Item Inventory[256];" array in the player's inventory, where they can store all sorts of assorted items. I can then use Inventory.GetName(); to read mName to tell the player what they're carrying in that particular slot by exploiting the virtual function. If I was to use constants (you're talking about global constants like gWEAP_GUN = 1; gWEAP_BOW = 2; etc. right?), I would need to use the Enum class for this purpose anyway.

Actually, that's all I can think of.

I am leaning towards changing it to your way, once I can clarify what exactly your way involves, and these issues are cleared up.

Thanks for your help, by the way, kikz. :-)

-----

kikz 
8/8/08 10:09:58 PM
Immortal

Quote by Meeko
What do you mean WEAP_CNT should be possible value instead of maximum number, kikz? I initialise an array with WEAP_CNT elements - enough to store all values for the enums. Then each element in the array stores the number of each particular weapon being carried. So mWeapons[WEAP_BOW] = 5; means they're carrying 5 bows.


You've defined WEAP_CNT as part of Weapons as a cheat to make it easier to ensure correct array size. The enumeration values in a enum should all be for the same conceptual domain. A Sword is a weapon. As is a Bow and Hammer. A Cnt is not a weapon.

Putting on my code reviewers hat, I'd want to see
 
const int NO_OF_WEAPON_TYPES = 4;
enum WeaponEnum
{
Sword,
Bow,
Hammer,
Teeth
};

You should be able to do
 
int weaponPos = (int)Sword; // cast to an int to get the array position.

It's a little nice in C#, where you can call the Enum class to return the number of enumerations in type :)

Anyway, in C++ your code might then be something like
 
class Player {
public:
Player();
void PickedUp(WeaponEnum w, int num);
int NumWeapons(WeaponEnum w) const;

private:
// not sure why unsigned long, that's a lot of weapons :p
int* Weapons;
};


Player::Player() {
weapons = new int[NO_OF_WEAPON_TYPES];

for (int index = 0; i < NO_OF_WEAPON_TYPES; i++)
weapons[index] = 0;

}

Player::~Player() {
delete [] weapons;
}

int Player::NumWeapons(WeaponsEnum w) {
int weaponPos = (int)w;

return weapons[weaponPos];
}

void Player::PickedUp(WeaponEnum w, int num) {
int weaponPos = (int)w;

weapons[weaponPos] += num;
}



Quote by Meeko
I am using the enums in header files that are shared among different classes that do different things with their weapons. There might be one lying on the ground, for example, and that's in the Ground class.

And I put in code to handle calls to WEAP_CNT.



Integer constants might be all right, but I think in practice it has similar flaws as defines compared to enums. For example:

1) If I remove a weapon from the list, I would have to change the value for WEAP_CNT and some other weapons. I have the choice between changing them all down one, or just changing the second-highest value (so if WEAP_CNT was originally 35, I change it to 34 and look for WEAP_BLAH = 35 and change that to the value I deleted). But that could get messy. It doesn't seem too bad, though...but enums do it automatically.

2) Type handling. I can create Weapon mName as a member, say, to make it easier to identify what the object is later on. This is useful for keeping track of inventory. For example, I create an Item class and a Weapon child class. I then create an "Item Inventory[256];" array in the player's inventory, where they can store all sorts of assorted items. I can then use Inventory.GetName(); to read mName to tell the player what they're carrying in that particular slot by exploiting the virtual function. If I was to use constants (you're talking about global constants like gWEAP_GUN = 1; gWEAP_BOW = 2; etc. right?), I would need to use the Enum class for this purpose anyway.

Actually, that's all I can think of.

I am leaning towards changing it to your way, once I can clarify what exactly your way involves, and these issues are cleared up.

Thanks for your help, by the way, kikz. :-)




Edited by kikz: 8/8/2008 10:11:52 PM

-----
Q6600 | 4Gb PC6400 | 2 x 500Gb RAID 0 + 2 x 320 Gb RAID 0 | 19" Benq FP591 + 24" Samsung 245B + 19" Dell | 8800GTS 640 Mb + 8400GS 256 Mb | Gigabyte GA-P35-DS3P | Antec P182 | Corsair HX-620 | Thermalright 120 Extreme | Vista x64

Kensey 
9/8/08 5:19:41 PM
Overlord

As an aside, while using a constant as the last item in an enum probably is a short cut that isn't technically correct, I remember doing a Uni assignment where we did just that. And it was how it was done in the sample solution given to us...

Something about fruits or fruit trees...
enum EnumFruit {apple, orange, banana, mango, MAX_FRUIT}


Though come to think of it, it was a rather an intro type course, so was probably that way to avoid the complexities (relatively) of doing things the "right way".

-----
All human beings are born free and equal in dignity and rights.They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood.

kikz 
9/8/08 5:40:53 PM
Immortal

Quote by Kensey
As an aside, while using a constant as the last item in an enum probably is a short cut that isn't technically correct, I remember doing a Uni assignment where we did just that. And it was how it was done in the sample solution given to us...

Something about fruits or fruit trees...
enum EnumFruit {apple, orange, banana, mango, MAX_FRUIT}


Though come to think of it, it was a rather an intro type course, so was probably that way to avoid the complexities (relatively) of doing things the "right way".


That's interesting actually. I get the benefits of using the enum method, however, it's a little hypocritical of C++ coders isn't it? VB6 and VB.NET to a much lesser extent makes life easier by allowing various shortcuts. It's those shortcuts that C++/C programmers cite when calling out VB and those that develop in it.

Thing is, using enum like that is probably all fine and dandy, as long as you know what's actually going on. Just like in VB. The flexibility is a positive if you understand what's actually happening behind scenes.

-----
Q6600 | 4Gb PC6400 | 2 x 500Gb RAID 0 + 2 x 320 Gb RAID 0 | 19" Benq FP591 + 24" Samsung 245B + 19" Dell | 8800GTS 640 Mb + 8400GS 256 Mb | Gigabyte GA-P35-DS3P | Antec P182 | Corsair HX-620 | Thermalright 120 Extreme | Vista x64

Kensey 
9/8/08 6:34:12 PM
Overlord

It was a number of years ago, so I can't remember the details of what exactly was taught, though having just had a quick look through a C++ book, the sections dealing with enums doesn't seem to use them with the constant at the end, so it may just have been the lecturers "bias"...

As to being hypocritical... don't blame me..., my main knowledge/experience is with Delphi (so I'm used to being looked down on).

-----
All human beings are born free and equal in dignity and rights.They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood.

Meeko 
12/8/08 5:54:23 PM
Titan

That sounds like a decent "correct" alternative, kikz. It might get annoying, though, having to count up all the elements in the enum manually.

I am still worried, though - technically speaking, C++ is not supposed to support something like:

int MyArray[ENUM_VALUE] should it? Or even something like MyEnumValue++

Or should it support these uses and I'm worrying about nothing?

I would like to be able to do it the correct way if possible. In your opinion, kikz, the inconvenience of having to count up the total of the enums to do:
const int NO_OF_WEAPON_TYPES = 4;

in your example, how inconvenient might it be? Perhaps we can shortcut by putting it after declaring the Enum and setting it to:

const int NO_OF_WEAPON_TYPES = Teeth+1;

perhaps?

-----

kikz 
12/8/08 7:53:46 PM
Immortal

Quote by Meeko
That sounds like a decent "correct" alternative, kikz. It might get annoying, though, having to count up all the elements in the enum manually.

I am still worried, though - technically speaking, C++ is not supposed to support something like:

int MyArray[ENUM_VALUE] should it? Or even something like MyEnumValue++

Or should it support these uses and I'm worrying about nothing?


I'd say the semantics is incorrect, even if the program compiles and works correcty. Enums are UDT's and shouldn't be used like that.

Quote by Meeko
I would like to be able to do it the correct way if possible. In your opinion, kikz, the inconvenience of having to count up the total of the enums to do:
const int NO_OF_WEAPON_TYPES = 4;

in your example, how inconvenient might it be? Perhaps we can shortcut by putting it after declaring the Enum and setting it to:

const int NO_OF_WEAPON_TYPES = Teeth+1;

perhaps?


won't work. consts can't be variable. If teeth is a constant it should be ok though.

-----
Q6600 | 4Gb PC6400 | 2 x 500Gb RAID 0 + 2 x 320 Gb RAID 0 | 19" Benq FP591 + 24" Samsung 245B + 19" Dell | 8800GTS 640 Mb + 8400GS 256 Mb | Gigabyte GA-P35-DS3P | Antec P182 | Corsair HX-620 | Thermalright 120 Extreme | Vista x64

Meeko 
12/8/08 8:40:24 PM
Titan

So we technically shouldn't be able to pass enum values to an array, kikz? I think that's the rule I have been happily breaking for a long time but should probably learn how to do it the right way.

But it's so convenient! What's the best alternative? Offhand, I think it's better just to use #define or constant ints instead of enums if that's the case (not being able to pass it to the array) - which means, of course, the mess with adding/deleting weapons from the list.

As for const int NO_OF_WEAPON_TYPES = Teeth+1; I meant when defining it. So it was originally const int NO_OF_WEAPON_TYPES = 4; but I edit the line to be = Teeth + 1; where Teeth is part of Enum Weapons {blah, blah, teeth};

But aren't enums technically not supposed to be able to used as numbers in the first place, making that incorrect?

So it seems that to be perfectly correct in C++, instead of using enums the way I have, I should stop using them for this altogether and use #define or constant ints. But that is still a bit less powerful. :-/

-----

kikz 
12/8/08 9:32:19 PM
Immortal

Depends on what your coding standard is :p

If your code compiles using enums and you don't have problem with it, use it. If you came to me for a code review though, I'd send you away for refactoring :)

-----
Q6600 | 4Gb PC6400 | 2 x 500Gb RAID 0 + 2 x 320 Gb RAID 0 | 19" Benq FP591 + 24" Samsung 245B + 19" Dell | 8800GTS 640 Mb + 8400GS 256 Mb | Gigabyte GA-P35-DS3P | Antec P182 | Corsair HX-620 | Thermalright 120 Extreme | Vista x64

Meeko 
13/8/08 3:48:40 PM
Titan

I want to learn the proper standard kikz, because I know I have been using the "wrong" one.

Really strict C++ compilers wouldn't even let use increment enums would they? For example,

MyEnum blah = EnumValue++;

is incorrect because enums shouldn't be treated as ints, right?

Argh, I don't know what to do. If I keep using enums like this, it's not supported on all compilers, but the alternative is to allocate constant integers manually.

-----

  1  
Forums | Programming