Usage of enum and char in switch statements - c++

I have a piece of code with enum as a parameter in the switch statement and it works as expected.
#include <iostream>
typedef enum
{
first=0, second=1, third, fourth, fifth, sixth
}enumValue;
void enumFunction(enumValue val)
{
switch(val)
{
case first : std::cout<<"1\n";
break;
case second : std::cout<<"2\n";
break;
case fifth : std::cout<<"5\n";
break;
default : std::cout<<"No value\n";
}
}
void main()
{
enumValue storeValue;
storeValue = fifth;
enumFunction(storeValue);
}
When I change the type of variable "storeValue" to a char the code still gives the same result as before. I am unable to figure out why does the code still work when the parameters being passed have been changed. Here is the code after making the changes to parameters.
#include <iostream>
typedef enum
{
first=0, second=1, third, fourth, fifth, sixth
}enumValue;
void enumFunction(char val)
{
switch(val)
{
case first : std::cout<<"1\n";
break;
case second : std::cout<<"2\n";
break;
case fifth : std::cout<<"5\n";
break;
default : std::cout<<"No value\n";
}
}
void main()
{
char storeValue;
storeValue = fifth;
enumFunction(storeValue);
}
Is the usage of char instead of an enum appropriate as they both give similar results when executed?? How does the second code work without any syntax errors??

C and C++ can implicitly convert between lots of types. In this case, the integral types int and char and your enum, etc. It's perfectly permissible to convert your enum value to a char and back again, so long as the values of your enum don't go over 127 (which they do not).
In C and C++, char and "8-bit integer" are basically the same thing. And it isn't an error to convert between bit-widths like int8_t (signed char), int16_t, int32_t, and int64_t.

In the enum, the elements first, second, third... have there corresponding values 0, 1, 2... which are of type int. char and int can be implicitly converted as long as the int value is in the valid range. So when you do
storeValue = fifth;
Then it is just storing the value of fifth in storeValue. And in the function, the switch statement is comparing the value.

Related

Casting invalid value to an enum via static_cast [duplicate]

This question already has an answer here:
What happens if you static_cast invalid value to enum class?
(1 answer)
Closed 7 months ago.
Doesn't static_cast protect against 'invalid' values to the type it's being cast to i.e Values here?
If so, it's not a good idea to print the casted value? How to ensure the print only takes place once the value is correct/valid?
enum class Values : uint8_t
{
One,
Two
};
void bar(uint8_t value)
{
Values val = static_cast<Values >(value);
printf ("The received value = %u\n", val);
switch(val)
{
case One: break;
case Two: break;
default: break;
}
}
int main()
{
bar(static_cast<uint8_t>(60));
}
Seemingly static_cast doesn't protect against 'invalid' values so in this snippet, how should the verification be done? Something like following or there's a better way?
enum class Values : uint8_t
{
One,
Two,
Max
};
void bar(uint8_t value)
{
Values val = static_cast<Values>(value);
if (val < Values::Max)
printf ("The received value = %u\n", val);
switch(val)
{
case One: break;
case Two: break;
default: printf ("invalid value!"); break;
}
}
No, there are no checks and there is nothing wrong with using a static_cast like this, no matter what the value is.
You specified that Values has underlying type uint8_t, so it is perfectly fine to (static_) cast between Values and uint8_t freely. There doesn't need to be a declared enumerator with a given value for the value to be valid for the enumeration. All values of the underlying type are also valid values of the enumeration type.
If you want to assure that the value is one of the enumerators, you need to write a function checking that yourself and decide on how it should act if the value does not satisfy the condition. (Should it throw an exception?)
(The rules are different if you don't specify an underlying type in an unscoped enumeration, in which case there is no fixed underlying type to substitute for uint8_t in the above and not all values of the implementation-defined underlying type are valid for the enumeration.)

Expression Syntax in Function Error Help! C/C++

Please help with my switch case I'm not sure on how I'm meant to put my functions in the cases. Do I keep the parameters in?
void ChoiceConvert(char unit){
char c, f;
printf("Enter your choice for converting from Kelvin\n1. 'c' to convert to Celcius\n2. 'f' to convert to Farenheit");
switch(unit)
{
case 'c':
ConvertCel(int temp, const int Freeze);
break;
case 'f':
ConvertFar(int temp, const int Freeze);
break;
default:
printf("\n");
}
return;}
This is the error I am getting.
Error E2188 state.cpp 53: Expression syntax in function ChoiceConvert(char)
Error E2188 state.cpp 56: Expression syntax in function ChoiceConvert(char)
There's a few issues with your code.
First: this function is meant to convert a temperature- you pass the char unit that you want it converted to- either C or F. SO
char c, f;
printf("Enter your choice for converting from Kelvin\n1. 'c' to convert to
Celcius\n2. 'f' to convert to Farenheit");
shouldn't be inside the function at all - it should be asked previous to the function, and then the answer is passed into ChoiceConvert.
Second: there's no temperature here. I assume you should ask the user that in main() as well, and pass that in as an argument as well as the unit.
Third: As stated by others, you're writing the function parameters, not its arguments. You should have the parameters (ie. the function declaration & definition) outside of this function, and then you CALL it within this function. Check this out in order to learn the difference between declarations, definitions, and calling. It's pretty vital base knowledge for programming.
Here's how I would do it:
int main()
{
char conversion;
int temperature;
printf("Enter your choice for converting from Kelvin\n1. 'c' to convert to Celcius\n2. 'f' to convert to Fahrenheit");
std::cin >> conversion; // requires #include <iostream>
printf("Enter the temperature you wish to convert:");
std::cin >> temperature; // requires #include <iostream>
ChoiceConvert(temperature, conversion); // calling the function
}
void ChoiceConvert(double temp, char unit)
{
switch(unit)
{
case 'c':
ConvertCel(temp);
break;
case 'f':
ConvertFar(temp);
break;
default:
printf("\n");
}
}
void ConvertCel(double temp)
{
// conversion here
}
void ConvertFar(double temp)
{
// conversion here
}
Also, UI side note- be careful: if you're looking for the user to input characters, making it a numbered list can be confusing.
When you are calling your conversion functions you are using their declaration instead of passing them actual values.
This is one of the offending lines:
ConvertFar(int temp, const int Freeze);
ConvertCel(int temp, const int Freeze);
You placed function signature instead of a statement. Twice.

Switching on scoped enum

I am trying to switch on a scoped-enum with the type unsigned int:
The enum is defined as:
const enum struct EnumType : unsigned int { SOME = 1, MORE = 6, HERE = 8 };
I receive a const unsigned int reference and I am trying to check that value against the enum values.
void func(const unsigned int & num)
{
switch (num)
{
case EnumType::SOME:
....
break;
case EnumType::MORE:
....
break;
....
default:
....
}
}
This results in a syntax error: Error: This constant expression has type "EnumType" instead of the required "unsigned int" type.
Now, using a static_cast on each switch, such as:
case static_cast<unsigned int>(EnumType::SOME):
....
break;
case static_cast<unsigned int>(EnumType::MORE):
....
break;
fixes the syntax error, although casting at each case statement doesn't seem like a good way to do this. Do I really need to cast at each case, or is there a better way?
You can solve this by casting the switch variable itself to EnumType:
switch (static_cast<EnumType>(num)) {
(Demo)
The purpose of scoped enums is to make them strongly-typed. To this end, there are no implicit conversions to or from the underlying type. You have to convert either the switch variable or the switch cases. I would suggest converting the switch variable since this requires less code and therefore will make maintenance easier.
IMO the correct solution would be to change the function to accept const EnumType & (or just EnumType) instead.

Calling C++ (member) functions dynamically

Suppose I have some reflection metadata, which has the following information:
enum class type { t_int, t_double, t_str /* etc... */ };
struct meta_data
{
void* function;
void* instance;
std::vector<type> param_types;
};
std::map<std::string, meta_data> ftable;
I would like to call functions in this map, given the function names and the parameters both as strings. My problem is not converting the parameters (e.g. with boost::lexical_cast), but casting to the right type of function pointer and invoking the function. If I allow possible 8 types and maximum 8 parameters, that's already a lot of branches in my code. What I want to avoid (pseudo code):
switch (md.param_types.size())
{
case 0:
cast function pointer, call it
break;
case 1:
switch (md.param_types[0])
{
case t_int:
int param = boost::lexical_cast(param_strings[0]);
cast function pointer, call with param
case ...
}
break;
case 2:
switch (md.param_types[0]) {
case t_int:
int param = boost::lexical_cast(param_strings[0]);
switch (md.param_types[1]) {...} // second param type..
}
break;
case n...
}
That blows up very quickly with the number of parameters and possible types. I'm looking for some solution along the lines of (pseudo code):
for (auto& p : paramter_strings)
{
convert p to a variable of matching type (type id comes from meta_data).
store value
}
call function with stored values
i.e. no branching for the function invocation. How can I do this with the least amount of boilerplate code (with possibly supporting arbitrary number of parameters)? You can think of this as creating bindings to a custom script language.
I came up with one approach.
Suppose you have a vector of unsigned int V and you know that
every element of the vector is a nonnegative number
which is less than N (or, say, 20).
Here is what you would call to change the vector V to a
positive integer:
n = sequence_to_code(V,N); // or n = encode(V,20U);
Here is the code.
long sequence_to_long(const std::vector<unsigned int> & L,
unsigned long n) {
long result = 0L;
std::vector<unsigned int>::const_iterator w=L.begin(),e=L.end();
if(w!=e) {
result += (*w)+1;
unsigned long the_pow = n;
unsigned int i = 1U;
++w;
while(w!=e) {
result += (*w+1)*(the_pow);
++w;++i;the_pow *= n;
}
}
return result;
}
Actually, I probably should have returned "unsigned long".
In addition, you can use this same routine with a program which creates
a text file. This text file would contain C++ code. Suppose you created
"the_defines.hpp". I will illustrate by example...
For example, say we have t_int=0; t_double = 1, d_str = 2
and there are only three types.
Then "the_define.hpp" could be the file:
#define TYPE_EMPTY 0U
#define TYPE_INT 1U
#define TYPE_DOUBLE 2U
#define TYPE_STR 3U
#define TYPE_INT_INT 4U
#define TYPE_DOUBLE_INT 5U
then this code could be used in the following
way:
std::vector<unsigned int> L;
// add entries to L
long n = sequence_to_long(L,3UL);
switch(n) {
case TYPE_INT:
std::cout << "an integer\n";
break;
case TYPE_INT_DOUBLE:
std::cout << "two args; first is an int; second is a double\n:
break;
}
Of course, you could create a text file which has the code for a very
long enum (if you care to avoid #define). For example,
enum class extended_type {
type_int,
type_double,
type_str,
type_int_int,
type double_int,
and so on.
You could also write a program which creates (one or more) text files.
These text files would also by C++ code. For example, your created file
could be:
swtich(n) {
case empty:
FILLIN
break;
case t_int:
FILLIN
break;
and so on until
case t_str_str:
FILLIN;
break;
}
I would also recommend casting using an inline function or a regular
function. For example,
inline int inside_int(foo f) {
const bar & b = * reinterpret_cast<const bar *>(f.pointer());
return b.d_x;
}
I recommend this due to DRY (don't repeat yourself) and being
able to search for all instances of the function.
I know that these program does not handle errors (overflow,
zero pointers, etc.)
Mark

Enum C++ Get by Index

I was wondering in C++ if I have an enum can I access the value at the second index? For example I have
enum Test{hi, bye};
if I want 'hi', can I do something like Test[0], thanks.
Yes and no. If your Enum does not have explicit values then it is possible. Without an explicit values, enum values are given numeric values 0-N in order of declaration. For example ...
enum Test {
hi, // 0
bye // 1
}
This means that indexes just translates into a literal value.
Test EnumOfIndex(int i) { return static_cast<Test>(i); }
This of course does 0 validation at runtime and as soon as you add an explicit value it will break down. But it will work in the default scenario.
Unless specified otherwise, enums start numbering at 0, and increment by 1 each entry.
enum Test
{
hi, //0
bye, //1
count //2
}
You can cast an int to the type of the enum to get the value you want, such as:
(Test)0;
//or
Test(0);
Which lets you do things like:
for(int i = 0; i < count; i++)
{
DoSomething((Test)i);
}
Enumerations map names to values. In your case, (int)hi would have a value of 0, and (int)bye a value of 1. You can use a cast to get the value of hi:
int myInteger = 0;
Test myValue = (Test)myInteger;
Note, though, that myValue could be an invalid enum value if myInteger is out of range.
No, but you could cast from int
Test test = (Test)0;
Depends what you mean by "I want 'hi'".
If you mean you want the value, then you can get it by casting an int, as others have said.
Casting a numeric literal to enum type is usually pointless - if you know which value you're expecting, you can use the name. That way, the enum can change without breaking your code. I guess it's possible that something really weird is going on, where someone has created an enum, and documented what "3" means but not which enum value it is. But then you'd want to fix the API.
Casting an integer value known at runtime to enum might be helpful if you have serialized data. As long as you know it's in range of the enum, the result is defined.
If you mean you want the string "hi", then you can't have it. Unlike Java, in C++ the names of the values in enumerated types exist only at compile time, not at runtime, and only map in one direction.
Your best option might be something like this:
enum Test{hi = 0, bye};
Then you can simply refer to 'hi' with the number 0, and 'bye' with 1.
Although this really defeats the whole purpose of using an enumeration in the first place.
If you are excepting the value to returned as {Hi or bye} ,then you cannot get the value like that .
i would not suggest this to be done inorder to get the actual value but it can be used as hack
string return_value(int index)
{
string temp = "";
switch (index)
{
case 1: temp = "hi"
break;
case 2: temp = "bye";
break;
defualt :
break;
}
return temp;
}
typecasting to enum would again return the index but you can assign to some other enum variable
#include <iostream>
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
#define FOREACH_TEST(ID) ID(hi) ID(bye) ID(good)
enum TEST { FOREACH_TEST(GENERATE_ENUM) };
static const char * Test[] = { FOREACH_TEST(GENERATE_STRING) };
int main() {
printf("%s ",Test[0]);
printf("%s\n",Test[bye]);
for (int i=0; i<2; i++) printf("Test[%d] = %s\n", i, Test[i]); }
compile and run with: g++ enum-test.cpp -o enum-test; ./enum-test
output:
hi bye
Test[0] = hi
Test[1] = bye