JKop said:
First I'm going to talk about enums. They're pretty much useless. For
instance:
you have some serious misconceptions about enumerations.
enum Month
{
Jan = 1,
Feb = 2,
Mar = 3,
Apr = 4,
May = 5,
Jun = 6,
Jul = 7,
Aug = 8,
Sep = 9,
Oct = 10,
Nov = 11,
Dec = 12
};
int main()
{
Month my_super_duper_month(13);
}
compiler error - illegal implicit conversion to int.
mind you:
Month m(static_cast<Month>(13));
would work. but that is a case of directly and maliciously circumventing
the enumeration.
So why are they useful? They're only merit is with switch statements:
switch (some_month)
{
case Jan:
//blah
case Feb:
//blah
}
The compiler can warn you when you leave one out of the switch statement.
Yipee!
what compiler? i would find it quite bizarre if a compiler barked that
warning at me, unless it had some crazy super verbose warning setting.
it is not an error, or even a mistake, to only switch on certain
enumerators.
Anyway, I'd suggest you return an "unsigned char" from this function. If you
want to give certain numbers special names, then by all means:
namespace ChocolateValues
{
const unsigned char no_error = 0;
const unsigned char multiple_errors = 1;
};
unsigned char SomeFunction()
{
return ChocolateValues::no_error;
}
and this has to be the wackiest suggestion of all, considering that you
write off enums for having an implicit conversion to int above (which
they don't, as i pointed out).
in fact, the example above is LESS robust than if it had used enums.
consider this:
////////////////////////////////////////////////////////
namespace error {
const unsigned char no_error = 0;
const unsigned char out_of_memory = 1;
const unsigned char cannot_open_file = 2;
}
enum type {
no_error,
out_of_memory,
cannot_open_file
};
void print_error(unsigned char c) {
// print error message based on error code
switch (c) {
case error::no_error: // whatever
case error:
ut_of_memory: // whatever
case error::cannot_open_file: // whatever
// ...
}
}
// nothing seems wrong with this...
unsigned char oops = 3;
// ...but
print_error(oops); // <--- what should this do?
////////////////////////////////////////////////////////
as opposed to:
////////////////////////////////////////////////////////
namespace error {
enum type {
no_error,
out_of_memory,
cannot_open_file
};
}
void print_error(error::type c) {
// print error message based on error code
switch (c) {
case error::no_error: // whatever
case error:
ut_of_memory: // whatever
case error::cannot_open_file: // whatever
// ...
}
}
error::type nope = 3; // won't compile
// this is explicit and obvious - the programmer knew what (s)he
// was doing, and should be able to explain him/herself
error::type iffy = static_cast<error::type>(3);
error::type ok = error:
ut_of_memory; // obviously ok
////////////////////////////////////////////////////////
enumerations are not perfect - personally, i was looking for a better
solution just last week, and i was not satisfied with the options - but
until the standard committee gives the thumbs up to the new super enums,
we're stuck with them. despite all their shortcomings though, i'd have
to say they're still a better choice than simple ints (or unsigned
char's for that matter).
indi