fail proof conversion of string to enum class - c++

I have an enum class like this (I am planning to add more options to it later):
enum class ViSequencePointType {
JumpToValue = 0,
RampToValue = 1
};
Then I have a configuration text file which each line supposed to represents one the enum values. Something like this:
1
0
255
A
WTF
I need to parse this file and create a vector of that enum class...so I do something like:
bool conversionResult = false;
int colThree = line.toInt(&conversionResult);
if(!conversionResult) {
//failed to convert to integer
} else {
ViSequencePointType pt = static_cast<ViSequencePointType>(colThree);
switch(pt) {
case ViSequencePointType::JumpToValue:
break;
case ViSequencePointType::RampToValue:
break;
default:
break;
}
for that default case the compiler says
Default label in switch which covers all enumeration values
which I believe it means if there is any invalid entry in the text file exists, I can not find it out!
So how can I approach this problem without letting any invalid enumeration slip through during runtime?

In order to cover invalid/nonsensical enum values, a common practice is to
rely on the fact subsequent enum values are implicitly assigned the value of the previous enum value + 1
add an "Invalid" enum value at the lowest value in the enum (implicitly 0, or you can assign it a low value such as -1)
add a "Max" enum value at the highest value in the enum
Here's an example:
enum class ViSequencePointType
{
Invalid = -1,
JumpToValue, // is implicitly assigned enum value 0 (-1 + 1 == 0)
RampToValue, // is implicitly 1 (JumpToValue + 1)
CrawlToValue, // etc...
HopToValue,
// add new values here
Max // Max must be the last value in the enum
};
Now when you parse your input value you can check the integral value is greater than Invalid and less than Max, and if so, you know it's a valid enum value
ViSequencePointType parse(const std::string& value)
{
bool converted = false;
int val = line.toInt(&converted);
if(!converted)
{
// do additional conversion failure handling here if necessary
return ViSequencePointType::Invalid;
}
if (val <= static_cast<int>(ViSequencePointType::Invalid) ||
val >= static_cast<int>(ViSequencePointType::Max)
{
// do additional out of bounds handling here if necessary
return ViSequencePointType::Invalid;
}
return static_cast<ViSequencePointType>(val);
}
Now you know the output from parse is a valid enum value, with the output for unknown/invalid values denoted by enum value Invalid.

Related

Using the TList class to reorder multiple fields

int __fastcall ListSortFunc1(void *Item1, void *Item2)
{
MyStruct *item1 = (MyStruct*)Item1;
MyStruct *item2 = (MyStruct*)Item2;
return (item1->string1 < item2->string1) ? (item1->string1 > item2->string1) :
StrToInt64(item1->number1) - StrToInt64(item2->number1);
}
Reading the online documentation, it is not very clear how to use the Sort method.
My need is to reorder two or more fields. Currently, I have to reorder a file where the first field is numeric, the second is the date, the third a string, the fourth still a string.
I did some tests with Excel and with the code that it reports, but I get completely different results.
Can anyone kindly provide me with directions?
TList::Sort() is passed a callback function that is called during sorting to compare pairs of values from the list. The callback is expected to conform to the specification of the TListSortCompare type. Per its documentation:
Item1 and Item2 are 2 elements from the list. When these are passed to the TListSortCompare function, the Sort method is asking which order they should be in. The comparison returns a value determined by the relative values of Item1 and Item2, as shown in this table:
Value
Description
>0 (positive)
Item1 is greater than Item2
0
Item1 is equal to Item2
<0 (negative)
Item1 is less than Item2
Your function does not satisfy that requirement.
When item1->string1 is less than item2->string1, you are returning 0 when you should be returning a negative value.
Otherwise, you return the result of subtracting item2->number1 from item1->number1. But you are comparing the number1 fields when item1->string1 is greater than or equal to item2->string1. You should be comparing the number1 fields only when the string1 fields are equal. Also, you are risking overflows by using subtraction if the number1 fields have large values.
Try something more like this instead:
int __fastcall ListSortFunc1(void *Item1, void *Item2)
{
MyStruct *item1 = static_cast<MyStruct*>(Item1);
MyStruct *item2 = static_cast<MyStruct*>(Item2);
if (item1->string1 == item2->string1)
{
// simply subtracting the values could lead to integer overflows
// for large values, so just compare the values as-is...
// Also: why are these not stored as __int64 to begin with?
__int64 int1 = StrToInt64(item1->number1);
__int64 int2 = StrToInt64(item2->number1);
if (int1 < int2) return -1;
if (int1 > int2) return 1;
return 0;
}
else
{
return (item1->string1 < item2->string1) ? -1 : 1;
// or:
return CompareStr(item1->string1, item2->string1); // case sensitive
// or:
return CompareText(item1->string1, item2->string1); // case insensitive
}
}

Return error code as double

I wonder if I can return error code as double in the following way in C:
double getValue()
{
double ret = 0;
if (error1)
{
return -1;
}
if (error2)
{
return -2;
}
return ret = ....;
}
int main(void)
{
double val = getValue();
if (-1 == val)
{
printf("getValue: error1\n")
return -1;
}
else if (-2 == val)
{
printf("getValue: error2\n");
return -2;
}
......
return 0;
}
so when the return value is >= 0 then it is correct value which can be used for calculations. When value is less than zero error occurred.
Will I get the floating-point-comparison problem when I compare return value with -1 or -2 ?
Flag values are a bad idea. Flag values that are floating point are doubly so, even if double precision.
If you are using IEEE double precision floating point values, the values -1 and -2 are exactly representable as doubles, and comparison is well defined. No "magic error" will slip in if you merely copy the double around or only read the value. In fact, on a system with conventional 2s complement 32 bit ints, every int can be represented exactly as a IEEE double precision floating point value.
Now, transformations you think wouldn't matter like x /3. * 3. will ruin the identity, so the code is very fragile: fragile both because flag values are fragile, and because floating point equivalence is often fragile in practice.
In C++, there are a myriad of ways to do this that are less fragile.
enum error_code {a,b,c};
boost::variant<double, error_code> getValue();
is a tagged union that can hold either a double or an error_code. There is a std::expected proposal you can look at which is a tagged union with a "bias" towards the first value being the only valid one (sort of a cross between std::experimental::optional and boost::variant).
Both of these result in the value being returned in a type-safe way, where an error is a different type of value than the non-error return type.
Alternative solutions include returning the error code separately (as the return value, or taking a pointer-to-error-code as a parameter (what I call ICU style)). The double could be set to some innocuous value in that case (say, NaN) rather than left uninitialized.
double getValue( error_code* e );
or
error_code getValue( double* out );
where enum error_code { a = -1, b = -2 } is an enumeration of the error codes.
#LightnessRacesinOrbit beat me to it, but having typed it I post it anyway.
You can do it by taking the value to be set as a pointer argument, and returning a status. That way, no values of *ret are barred.
int getValue(double *ret)
{
*ret = ...;
if (error1)
return -1;
if (error2)
return -2;
return 0;
}
Then the calling code can be such as
double myval;
int err;
if ((err = getValue(&myval)) == 0)
printf ("getValue() returned %f\n", myval);
else
printf ("getValue() returned error %d\n", err);
Yes, you could get floating-point errors.
So consider using exceptions instead, or perhaps return an int error code and populate a double "out parameter" on success:
int getValue(double& ret)
{
if (error1)
return -1;
if (error2)
return -2;
ret = ....;
return 0;
}
Doing that is not necessary and makes error handling difficult, you should create an enum where you can add or remove error codes as needed, and also you don't really need to remeber what -1 is or what does -2 mean, just give each error a descriptive name, and do this
enum ErrorCodes {NoError, Error1, Error2, ... , ErrorN};
enum ErrorCodes getValue(double *value)
{
if (error1)
return Error1;
if (error2)
return Error2;
.
.
.
if (errorN)
return ErrorN;
*value = resultOfCalculation;
return NoError;
}
then
enum ErrorCode code;
double value;
code = getValue(&value);
switch (code)
{
case NoError:
/* use value here */
break;
case Error1:
/* handle error 1 */
break;
/* and so on */
}
I think this is a lot better and elegant, because you can apply it anytime you want to have robust error checking, no matter what type the target value is, this would work exactly the same for a struct or a double or an int array.

switch case on char*

It is a piece of code that gives me error:
const char* name = pAttr->Name(); // attribute name
const char* value = pAttr->Value(); // attribute value
switch(name) // here is where error happens: must have integral or enum type
{
case 'SRAD': // distance from focal point to iso center
double D = atof(value);
break;
case 'DRAD': // distance from iso center to detector
break;
default:
break;
}
The switch(name) is where error happens. It says it must be a integral or enum type. So how do I do switch case, or equivalent, on a char* type?
You cannot use switch here; as the error says, const char* is not supported. It's a good thing, too, because comparing two C-strings through pointers only compares the pointers, not the strings they point to (consider "hello" == "world").
Even if it were, you're trying to compare your C-string to multicharacter literals, which is certainly not what you intended, not least of all because they have type int and an implementation-defined value; I guess you meant to write "SRAD", not 'SRAD'.
Since you're using C++, you should do this:
const std::string name = pAttr->Name();
const std::string value = pAttr->Value();
if (name == "SRAD") {
double D = atof(value.c_str()); // use std::stod(value) in C++11
// ...
}
else if (name == "DRAD") {
// ...
}
else {
// ...
}
(I also fixed your use of name in the initialisation of D; Remy's right — you must have meant value here since "SRAD" cannot possibly be interpreted as a double.)
Another option is to use a local map to store integral values corresponding to the string values, get the integral value from the string, then, use switch on the integral value.
enum { SRAD = 1, DRAD, ... };
static std::map<std::string, int> localMap;
// Fill up the map.
if ( localMap.empty() )
{
localMap["SRAD"] = SRAD;
localMap["DRAD"] = DRAD;
}
const char* name = pAttr->Name(); // attribute name
const char* value = pAttr->Value(); // attribute value
int val = localMap[name];
switch (val)
{
case SRAD: // distance from focal point to iso center
{
double D = atof(value);
break;
}
case DRAD: // distance from iso center to detector
break;
default: // name is unknown
break;
}
Ok, this is totally, completely EVIL, but I have done it, and it does work:
// Must be a #define because an inline func won't give you a constant
#define MAKECODE(p) ((((p)[0])*0x01000000) \
+ (((p)[1])*0x00010000) \
+ (((p)[2])*0x00000100) \
+ ((p)[3]) )
// Note: I did not verify that the parenthesis matched.
switch(MAKECODE(name))
{
case MAKECODE("SRAD"): // distance from focal point to iso center
double D = atof(name);
break;
case MAKECODE("DRAD"): // distance from iso center to detector
break;
default:
break;
}
NOTE: BAD things will happen if the string name points to is less than 4 characters. Different bad things will happen is the string in the case statements are less than 4 characters (but probably just a compiler error).
this answer posted mostly for fun, but it will work if your name string is guaranteed to always be 4 bytes long.
#include <iostream>
using namespace std;
// precondition: name is exactly 4 chars in length
uint32_t convert(const char* name)
{
uint32_t val = uint32_t(name[3])
+ (uint32_t(name[2]) << 8)
+ (uint32_t(name[1]) << 16)
+ (uint32_t(name[0]) << 24);
return val;
}
int main()
{
const char* name = "SRAD"; // attribute name
const char* value = "10"; // attribute value
switch(convert(name)) // convert the string value to integral type uint32_t
{
case 'SRAD': // use arcane knowledge of C to construct an int32 representation of ascii digits
{
double D = atof(value);
cout << "SRAD " << D << endl;
break;
}
case 'DRAD': // distance from iso center to detector
cout << "some operation on value here " << endl;
break;
default:
break;
}
return 0;
}
A switch statement can only evaluate an expression of an integral or enumeration type (or convertible to such a type), and the expression in each case label must be a constant expression.
'SRAD' is not a string literal. It's a character literal with an implementation-defined value of type int. (This is a nearly useless language feature that I've seen used by mistake more than I've seen it used correctly.)
If you want to use C-style language features, avoiding things like C++'s std::string, the equivalent would be an if/else chain:
if (strcmp(name, "SRAD") == 0) {
// ...
}
else if (strcmp(name, "DRAD") == 0) {
// ...
}
else {
// ...
}
If you use std::string (which is advisable), the code would be similar, except that you can use == rather than strcmp.
You could set up a data structure that lets compute a discrete value that you can then use in a switch/case statement, as R Sahu's answer suggests. This would save the overhead of potentially doing N string comparisons. In my opinion, that would be overkill for a simple case like this. If your actual code is larger and more complex, it's worth considering.
Or you might consider redesigning your data structure so that you store and test an enumeration value directly, and then get a string value from that enumeration value via a lookup table.

Creating a bound on a value within the program

I am currently writing a program that will take in a lot of user input and as a result will change certain variables.
What I am trying to accomplish is to set a bound for these values, such as the variable "age" of the object cannot exceed 50 and is greater than or equal to 0.
range: [0, 50]
What would be the best way to the best way to set a maximum for the value?
For example:
age = 46
age = age + 10 // new value of age would be 50 as that is the maximum.
I know I could implement this with if statements within the scope of the operations
if (age > 50) {age = 50;}
else if (age < 0) {age = 0;}
following the operation to change the value.
I am going to be dealing with many different variables within the structure such as age, hunger, happiness, etc. and would rather not have to repeat the if statements for each one.
Is there a way I can define bounds on the variables previously and if it ever leaves the bounds it throws an error or returns a variable?
If it helps my current implementation of the changing of values is:
with an enum 'Operation' defining the operations seen below.
int modifyHunger(Operation operation, int value)
{
switch(operation)
{
case INCREMENT:
myHunger = myHunger + value;
break;
case DECREMENT:
myHunger = myHunger - value;
break;
case REINIT:
myHunger = 0;
break;
case INIT:
myHunger = value;
break;
default:
break;
}
return myHunger;
}
There are several ways to tackle this question, but my personal choice is using min and max over direct conditionals. So for example we can implement a function to clamp values like this:
template <typename T>
T clamp(const T &value, const T &lower, const T &upper)
{
return max(lower, min(value, upper));
}
The advantage to this method is that it is generalized for any type which can be used with min and max.
Edit:
Just to expand on the idea further you can also make a class which overloads basic math operators and implicitly calls clamp. Which can be even more elegant, and in that case probably won't need a template.
It's up to you to expand this into something comfortable for your taste and use case.

How to get next value of enum

I have the following problem:
enum Language { English, French, German, Italian, Spanish };
int main() {
Language tongue = German;
tongue = static_cast<Language>(tongue + 1);
cout << tongue;
}
//it returns 3.....but i want to get the language name on index 3.....
I find that an explicit look up table works best, for both converting from enum to text and text to enum:
enum Language_Enum
{
LANGUAGE_FIRST = 0,
LANGUAGE_GERMAN = LANGUAGE_FIRST,
LANGUAGE_ENGLISH,
LANGUAGE_HOPI,
LANGUAGE_WELSH,
LANGUAGE_TEXAN,
LANGUAGE_DUTCH,
LANGUAGE_LAST
};
struct Language_Entry
{
Language_Enum id;
const char * text;
};
const Language Entry language_table[] =
{
{LANGUAGE_GERMAN, "German"},
{LANGUAGE_HOPI, "Hopi"},
{LANGUAGE_DUTCH, "Dutch"},
// ...
};
const unsigned int language_table_size =
sizeof(language_table) / sizeof(language_table[0]);
Specifying the enum along with the text, allows for the enum order to change with minimal effect to the search engine.
The LANGUAGE_FIRST and LANGUAGE_LAST identifiers allow for iteration of the enum:
Language_Enum l;
for (l = LANGUAGE_FIRST; l < LANGUAGE_LAST; ++l)
{
// ...
}
You'll have to create an array of strings which matches your enum e.g.
std::string[] LangTxt = { "English", "French", "German", "Italian", "Spanish" };
then you can reference them as follows:
cout << LangTxt[tongue];
Be careful to keep the definitions together though so they are updated side by side.
It is not so simple to print the enum name for a given enum value in C++. Instead, you can use a map or string array to hold the values, which do allow you to get both the index and the string value.
Best Way to use enum is first give initial value to your enum.
enum TestEnum
{
Zero=0,
One,
Two
}
Even you wont specify anything the default starting index is zero.
To get the value at a particular index simple do that
TestEnum(index);