Switching on scoped enum - c++

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.

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.)

how to use a rvalue reference in a switch's case

I want to use t(rvalue reference) in a case of switch(T), but I get an error the value of 't' is not usable in a constant expression. How to do it the right way.
#include <iostream>
using namespace std;
int main(){
int (&&t)=5;
int T{};
switch(T){
case t: // error in this case
cout<<t<<endl;
break;
default:
cout<<"default"<<endl;
break;
}
}
Note that case labels in a switch statement need to be constant expressions.
You can't use an rvalue reference as a case label, since it is not a constant expression. You can however use a compile time initialized variable:
constexpr int t = 5;
switch(...)
{
case t : ... // ok
}
Note that trying to do something like:
int const &&t = 5;
will not work either, since the initializer is not a constant expression, so there is no way that I'm aware of that lets you use an rvalue reference as a case label.
Note also, that something like:
int const t = ...
will not work unless the initializer is a constant expression (i.e. known at compile time). So:
int const t = 5;
will work, but:
int n = 5;
int const t = n;
will not.

Correct way to convert an enum to value

I work on a project that has a lot of enums defined like this:
enum BundleSize
{
BUNDLE_SIZE_5 = 5,
BUNDLE_SIZE_10 = 10,
BUNDLE_SIZE_107 = 107,
};
I wrote a function to get the value from it like:
int convertBundleSizeEnumToVal(BundleSize b)
{
switch(b)
{
case BUNDLE_SIZE_5: return 5; break;
case BUNDLE_SIZE_10: return 10; break;
case BUNDLE_SIZE_107: return 107; break;
default: // handle appropriately and error out
}
}
I realize I don't really need a converter (method 1 and 2 both work below):
BundleSize b = getRandomBundleSize();
printf("The size is %d\n", convertBundleSizeEnumToVal(b)); // method 1
printf("The size is %d\n", b); // method 2
But I feel that method 1 is still the "correct" way to do this, because in the future something like this might come along:
enum BundleSize
{
BUNDLE_SIZE_5 = 5,
BUNDLE_SIZE_5_POINT_5 = 6,
BUNDLE_SIZE_10 = 10,
BUNDLE_SIZE_107 = 107,
};
Which now effectively breaks method 2 without an obvious runtime error, whereas method 1 will atleast catch the problem in the default switch case.
I'm curious about what people think is the right way to handle these conversions.
You can use the static_cast operator:
static_cast<int>(b)
IMO, this is "correct". You shouldn't be defining functions to convert every possible enum variant to an integer, especially with large enums.
Actually, you are using simple enum, so you can simply use your enum variable as a value.
For enum class (strict version of enum) you should use static_cast to convert your enum to value.
You can simplify your function to:
int convertBundleSizeEnumToVal(BundleSize b)
{
switch(b)
{
case BUNDLE_SIZE_5:
case BUNDLE_SIZE_10:
case BUNDLE_SIZE_107:
return b;
default: // handle appropriately and error out
}
}
Method 2, is broken because the underlying type of enum is not necessarily int, and so the format specifier %d may be wrong and behaviour of the program may be undefined.
You can cast the enum value to int first, and it will be correct as long as you don't use higher values than can be represented by int. You can use either static_cast or explicit cast. Or you can use an implicit conversion:
int value = getRandomBundleSize();
printf("The size is %d\n", b);
Regarding which you should use, well it depends on what you need. If you think that enum values added later should not be converted by convertBundleSizeEnumToVal but should result in an error, then method 1 is indeed superior.
If you wish all enum values to be converted, then the function is error prone, as you would have to remember to add a case each time a new value is added. In this case method 2 is superior.

Usage of enum and char in switch statements

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.

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