switch case on char* - c++

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.

Related

Convert a boring list of switch statements to something shorter and pleasing to look at?

I have a switch statement that runs like this
switch (abc) {
case FILE_0:
lf = m_a->olf[0];
kf = m_a->pkf[0];
break;
case FILE_1:
lf = m_a->olf[1];
kf = m_a->pkf[1];
break;
.
.
default:
LOG_ERR << "Wrong type to check";
return 0;
}
This happens about 30 times and i end up with 30 cases in this single switch.
Any way to shorten it in C++ 11 ? E.g. using templates.
Your code ain't that big to be sure about the intent, though, from what I can see in the snippet, you actually want to convert the symbolic value into an index. (Can I assume this is an enum?)
What I would do is to move that code into a separate function:
auto fileEnumToIndex(FileEnum file) {
switch (file) {
case FILE_0: return 0;
case FILE_1: return 1;
default: __builtin_unreachable();
}
}
Your code than changes to:
auto index = fileEnumToIndex(abc);
lf = m_a->olf[index];
kf = m_a->pkf[index];
If the FileEnum is a real enum, you can change the code in the function fileEnumToIndex to a simple static_cast
To cover the default case, you could return a std::optional and use the std::nullopt case to do some error handling. However, when FileEnum is an actual enum, I would assume error handling when you determine that value.
You can create a map of abc and the indice and use that for determining the indice.
// somewhere, maybe outside functions
static const std::unordered_map<abc_type, int> table = {
{FILE_0, 0},
{FILE_1, 1},
...
};
// inside function
auto idx_itr = table.find(abc);
if (idx_itr != table.end()) {
lf = m_a->olf[*idx_itr];
kf = m_a->pkf[*idx_itr];
} else {
// default case
}

fail proof conversion of string to enum class

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.

C++ indexed access to structure variables of different types

I have a number of bool and int variables, that I need to access by some sort of index. I found a way to do so, but it seems a bit too complicated. Is there a way to do this in more elegant way?
For now in header file I have structure
struct FDialogueFlags
{
bool tmpFlag1;
bool tmpFlag2;
// bool tmpFlagX;
int tmpState1;
int tmpState2;
// int tmpStateX;
};
and enumeration
enum class Eflags
{
// NAME = flag_ID,
TMP_FLAG_1 = 1,
TMP_FLAG_2 = 10,
// TMP_FLAG_X = XX,
TMP_STATE_1 = 101,
TMP_STATE_2 = 110,
// TMP_STATE_X = XXX,
};
And in source file I have function, that returns values for given index - flag_ID
int GetFlagValue(int flag_ID)
{
switch (Eflags(flag_ID))
{
case (Eflags::TMP_FLAG_1):
return flagsAndStates.tmpFlag1;
break;
case (Eflags::TMP_FLAG_2):
return flagsAndStates.tmpFlag2;
break;
/*case (Eflags::TMP_FLAG_X):
return flagsAndStates.tmpFlagX;
break;*/
case (Eflags::TMP_STATE_1):
return flagsAndStates.tmpState1;
break;
case (Eflags::TMP_STATE_2):
return flagsAndStates.tmpState2;
break;
/*case (Eflags::TMP_STATE_X):
return flagsAndStates.tmpStateX;
break;*/
default:
break;
}
}
That way everytime I need to add new "flag" or "state" I have to edit 3 places in my code.
Besides, if I need to access any "flag" or "state" by it's name written in enum, I can not do so, because Eflags (TMP_FLAG_1) returns TMP_FLAG_1 and not a number.
The other important thing, I'd like to keep variable namings, there might be up to hundred of this "flags" and "states" and it's crusial for them to have unique names and not just iterative numbers (Code above is just an example, in the end product I would name all of them according to their meaning)
If possible I'd like to avoid using std::map since it isn't supported natively by UE4.
So, the core idea is to access certain amount of variables of different numeric types by given number, possibly keeping variable naming.
Assuming you are asking for syntactic alternatives, Can you use tuples? Here - http://en.cppreference.com/w/cpp/utility/tuple
They are similar to structures and you can use std::get to retrieve values with index-based method. You can then use if statements for comparisons instead of switch statement.
Example -
#include <iostream>
#include <tuple>
int main()
{
auto t = std::make_tuple(1, true, 25);
std::cout << std::get<0>(t) << "\n"
<< std::get<1>(t) << "\n"
<< std::get<2>(t) << "\n";
}
IDEONE
I don't have any experience with UE4 and what native support means, but there are numerous drop-in alternatives to std::map like this one.

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.

Assign values based on variable name in a string

Weird question and hard to word but lets say I have a 2 files that have a string of what double variables will appear in the file at the top and then the corresponding double variables, something like:
File1 =
A B C D E
1.2 3.4 4.5 5.6 7.8
File2=
B D E
9.8 7.6 5.4
and I have a struct of doubles
struct numb{
double A,B,C,D,E};
is it possible to read in the string in file 1 (A B C D E) and whatever the first value in the string is (A) assign it to the corresponding struct value numb.A.
So then the next file it will read in the first value of the string (B) and assign it to numb.B.
I realize this is possible with a bunch of if statements but I was wondering if there is an easier way. The hardest part is the string of variables will always be some combination of A,B,C,D,E. I am programming in C++ VS10
You can create a map with the string to parse as the key, and a pointer to member of the corresponding attribute of your structure as the value.
std::map<std::string, double numb::*> mapLetterToCorrespondingAttribute;
Then parse your file and assign the value to the corresponding member pointed to by the value in your map corresponding to the key being the letter you parsed.
Read this multiple times before you say you don't understand :D
A switch is probably the easiest way to do this.
void set_member(numb &n, char member, double value)
{
switch (member) {
case 'A':
n.A = value;
break;
case 'B':
n.B = value;
break;
// etc.
default:
// handle error
}
}
Declare an array of double in struct numb.
struct numb {
void setValue(char label, double val) { value[label-'A'] = val; }
double getValue(char label) const { return value[label-'A']; }
double value[5];
};
Then, you could perform:
numb n;
n.setValue('A', 1.2);
double A = n.getValue('A');
Read the two lines into std::vector<std::string> and then put them into a map in pairs:
std::vector<std::string> vars; // the split up first line
std::vector<std::string> values; // split up second line
std::map<std::string, double> mapping;
for (int i = 0; i < vars.size(); ++i) {
mapping.insert(std::make_pair(vars[i], boost::lexical_cast<double>(values[i]));
}
If you pre-populate the map mapping with sensible default values, this should be quite simple. Also, you can substitute the call to boost::lexical_cast<double> with any conversion method you like.