Safely convert enum class from underlying type - c++

Let's say I have a strongly typed enum type like this:
enum class message : int {
JOIN = 0,
LEAVE = 4,
SPAWN = 1,
}
And I need to safely (safely in this case means discarding invalid variants) convert it from it's underlying type (int).
For this purpose, I have a function to convert it for me:
std::optional<message> get_message(int num) {
return num == (int)message::JOIN || num == (int)message::LEAVE || num == (int)message::SPAWN ? (message)num : {};
}
This works, but is long to write and prone to mistakes, especially for enums with a larger number of variants.
Is there a way to automate this process in C++17?

Talking about underlying type, we notice that this class merely obtains a type using another type as model, but it does not transform values or objects between those types.
As an option to simplify the function you could work by iterating in the enum,or as others said before with some type of container, by iterating the same enum as an example here: How can I iterate over an enum?
and more information about enum just in case: https://learn.microsoft.com/en-us/cpp/cpp/enumerations-cpp?view=vs-2019

Related

Is there a way to store auto value in c++ map? [duplicate]

This question already has answers here:
C++ std::map holding ANY type of value
(8 answers)
Closed 1 year ago.
Hey I'm new with c++ and I'm trying to create a map wich can store multiples types :
map<sting, `auto`> test_map;
test_map["first elem"] = 1;
test_map["second elem"] = 'c';
Wich obviously gets me some errors.
I've been looking a bit online and I have found interesting things but not an answer. Maybe I miss a bit of c++ vocabulary.
I would also try with some kind of class wich stores about any types and I don't know if it can works.
map<string, `my_class`> test_map;
map["first_elem"] = my_class("string");
map["first_elem"] = my_class(12);
Thank you for helping !
The auto keyword doesn't mean you can assign multiple value types to the same storage, it's merely an automatic type deduction tool in c++ useful when you deal with complex type names or purely unwritable types (such as capturing lamdas) eg.:
void foo()
{
bool b = true;
auto l = [&]() -> bool { return !b; };
}
If you want to store values of different (or any) types in the same storage space try using either std::varian or std::any (both require c++17 or higher).
std::variant allows you to store one of the earlier specified types and doesn't do additional allocations (it's size is enough to hold any object of specified type). It's a type safe alternative to unions.
void foo()
{
std::map<std::string, std::variant<int, float, char>> c; // this can only map int, float and char to std::string
}
std::any can store any type you want but will allocate when necessary.
void foo()
{
std::map<std::string, std::any> c; // this can map any type of value to std::string
}

How to have a tri-state 'boolean' in c++

What is the best way to have three value Boolean variable in c++?
I would like to have fields set to true, false or not set at all in my array.
If I declare them this way:
t[0] = true;
t[1] = false;
t[2] = NULL;
When I test the condition I get:
t[2] is false
You might want to look at boost.tribool: http://www.boost.org/doc/libs/1_60_0/doc/html/tribool.html
This should work:
t[0] = true;
t[1] = false;
t[2] = -1;
Or if you only need 3 states but perhaps would like more at some point, an enum is great:
enum STATES
{
NULL_STATE = -1, // you can manually specify -1 to give it a special case value
FALSE, // will be equal to 0
TRUE // will be equal to 1
};
No matter what though, 0/false is the only thing that returns false in an if() statement. -1 and true both return true.
You may want to use a switch like this to deal with 3+ states:
switch (var) // may need to cast: (int)var
{
case 1:
case 0:
case -1:
};
Alternatively if you want to stick to an if statement block, you could do something like this:
if (var == -1) // or (var == NULL_STATE)
{}
else if (var) // true condition
{}
else // false
{}
Consider using std::experimental::optional<bool> (if your C++ standard library has it), or boost::optional<bool> (www.boost.org).
I believe std::optional is a candidate for C++17 so if you adopt one of the above then your refactoring effort to C++17 ought to be minimal.
If you don't like using things that are not (yet?) in the "proper" C++ standard library, then consider
Something based around std::unique_ptr<bool>
A std::pair<bool, bool>
A good old-fashioned enum with 3 values.
You could use boost::optional
http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/index.html
boost::optional<bool> myBooleanVariable;
I agree that tribool can be better if you don't need the uninitialised values to be NULL. Where comparing optional and tribool, the documentation says:
First, it is functionally similar to a tristate boolean (false, maybe, true) —such as boost::tribool— except that in a tristate boolean, the maybe state represents a valid value, unlike the corresponding state of an uninitialized optional. It should be carefully considered if an optional instead of a tribool is really needed.
Source: http://www.boost.org/doc/libs/1_60_0/libs/optional/doc/html/boost_optional/a_note_about_optional_bool_.html
What is the best way to have three value Boolean variable in c++?
Boolean values by definition only have 2 possible states - True or False.
If you want to have another state for 'invalid' or 'not set' then you need to encapsulate the bool variable in some other data-types.
The right solution depends on what you want to do with that variable.
For simple comparisons (if-else and switch) scoped enums (c++11) should be preferred.
enum class tristate{true,false,undefined=0};
They are simple, easy to use and understand and offer type safety over plane old enums. As they are type-safe you can not accidentally compare it with different types of enums or numeral types, But it also means you can not use bitfiddling and integer-tricks either.
Unless a different type is specified an enum class is a numerical type which gets initialized to '0'. that means by assigning the value '0' to one of the enum-values you can make that the default state.
tristatet[7];
t[1] = tristate::true;
t[2] = tristate::false;
t[3] = tristate::undefined;
t[4] = false; //error
t[5] = 0; //error
t[6] = null; //error
t[0] == true; //error
t[0] == tristate::true; // false
t[0] == tristate::undefined; // true
Of course you can use that in a switch-statement:
switch(t[2]) {
case tristate::true:
foo(); break;
case tristate::false:
bar(); break; //t[2] was set to tristate::false
case tristate::undefined :
doNothing(); break;
}
You can use std::optional for this:
std::optional<bool> t[3];
t[0] = true;
t[1] = false;
t[2] = std::nullopt;
for (auto const& i : t)
if (i.has_value()) std::cout << i.value() << '\n';
output:
1
0
I also believe an enum declaration is the cleaner and simplest solution.
A small note on the size of the new type: enums are usually (depending of course on the compiler) backed by integers, so you are allocating something like 32 or 64 bits to actually use 2 bits.
In newer C++ (C++11), you can specify the underlying type of the enum (to an existing integral type). For example:
enum tribool: uint8_t {False = 0, True = 1, Unknown = 2};
...
enum tribool f = tribool::False;

Heterogeneous array implementation

I would appreciate your help!
Which data structure is used to implement heterogeneous array in C or C++ ? The array may contain any standard data types like int,float, char, string etc...
As ravi mentions, the appropriate data structure is called a tag-union (also called variant record). One way to implement it is this:
typedef union {
int tag;
struct {
int tag;
int val;
} int_;
struct {
int tag;
double val;
} double_;
} object;
Then you can make an array of these.
object arr[5];
You use the tag field to indicate which union member is in use. Typically with an enum.
enum type { INT, DOUBLE };
Then set the tag when creating the object, and check the tag before accessing. This can be encapsulated by using constructor functions.
object new_int(int i){
object ret;
ret.tag = INT;
ret.int_.val = i;
return ret;
}
object new_double(double d){
object ret;
ret.tag = DOUBLE;
ret.double_.val = d;
return ret;
}
And you usually want to use a switch on the tag for accessing, writing a different case for each type.
void print_object(object x){
switch(x.tag){
case INT: printf("%d\n", x.int_.val); break;
case DOUBLE: printf("%f\n", x.double_.val); break;
}
}
Or in some circumstances, you may want to fold the array into a single type so it can be accessed without checking the tag each time.
for (i = 0; i < sizeof arr/sizeof*arr; i++)
if (arr[i].tag == INT)
arr[i] = new_double(arr[i].int_.val);
There is no such array in c++ which can store elements of different types nor there is container in stl. Although there's one way to store different element in a container but condition is those types should be related through inheritance.
In C there's a concept called tagged union which can store different types giving tag as a means to specify which variable is actually there.
One more way to do this is using an array of void* pointers. Although that would be quite ugly C++. This would not be truly heterogeneous as you are using a type of pointer that any pointer can be cast into. It is similar to making a collection of base class type and then storing objects of derived classes.
This I got from Stroustrup article:-
If you need a heterogeneous container in C++, define a common interface for all the elements and make a container of those. For example:
class Io_obj { /* ... */ }; // the interface needed to take part in object I/O
vector<Io_obj*> vio; // if you want to manage the pointers directly
vector< Handle<Io_obj> > v2; // if you want a "smart pointer" to handle the objects
Apart from that Boost::Any can also be used:-
vector<Any> v;
I guess you could keep an array of pointers to anything
void* stuff[size];
const char* str = "hello";
int x = 20;
int *array = malloc(sizeof(int) * 5);
stuff[0] = str;
stuff[1] = &x;
stuff[2] = array;
Alternatively, an array of unions if you knew all the types before hand.

Using enum in loops and value consistency

I'm a big fan of C++'s strong-typing features and what I like the most is to use enumerations while dealing with limited sets of data.
But enumerations lack some useful features, for example operators:
enum class Hex : int
{
n00, n01, n02, n03,
n04, n05, n06, n07,
n08, n09, n10, n11,
n12, n13, n14, n15
};
for (Hex h = Hex::n0; h <= Hex::n15; ++h) // Oops! no 'operator ++'
{ /* ... */ }
Is easy to get rid of the lack of operators creating a free operator on the same scope:
Hex &operator ++(Hex &h)
{
int r = static_cast<int>(Hex);
h = static_cast<Hex>(r + 1);
return h;
}
for (Hex h = Hex::n0; h <= Hex::n15; ++h) // Now the '++h' works!
{
std::cout << std::dec << int(h) << ": "
<< std::hex << int(h) << '\n';
}
But this approach is more a nuisance than a solution, because it can break the value limitation of the enumeration: applying ++h while h equals to Hex::n15 will set h to he value 16, wich is out of the Hex scope of values while h is still of the type Hex!, This problem is more evident in other enumerations:
enum class Prime : int
{
n00 = 2, n01 = 3, n02 = 5, n03 = 7,
n04 = 11, n05 = 13, n06 = 17, n07 = 19,
n08 = 23, n09 = 29, n10 = 31, n11 = 37,
n12 = 41, n13 = 43, n14 = 47, n15 = 53
};
Prime &operator ++(Prime &p)
{
// How to implement this?! will I need a lookup table?
return p;
}
This problem was a surprise for me; I was betting that storing an incorrect value into an enumeration value will throw an exception. So, for now I was wondering if there's an elegant way to deal with this enumeration's weaknesses, the goals I want to achieve are:
Find a comfortable way to use enumeration values in loops.
Ensuring enumation data consistency between operations.
Additional questions:
Is there a reason for not throwing an exception when an enumeration data gets a value that is out of its possible values?
There is a way to deduce the type associated with an enumeration class?, the int type in the enumerations Hex and Prime.
As you've noticed, enum in C++ is not an enumerated type,
but something more complex (or more mixed). When you define an
enum, you define in fact two things:
An integral type with a legal range sufficient to contain an
or of all of the enumerated values. (Technically: the range
is 2^n - 1, where n is the number of bits necessary to
hold the largest value.)
A series of named constants having the newly defined type.
(I'm not sure what happens with regards to the range if you
explicitly specify an underlying type.)
Given your enum Prime, for example, the legal values would be
all integers in the range [0...64), even if all of these
values don't have a name. (At least if you didn't specifically
say that it should be an int.)
It's possible to implement an iterator for enums without
initializers; I have a program which generates the necessary
code. But it works by maintaining the value in an integral type
which is large enough to contain the maximum value plus one. My
machine generated implementations of ++ on such an enum will
assert if you try to increment beyond the end. (Note that
your first example would require iterating h one beyond the
last value: my implementation of the various operators does not
allow this, which is why I use an iterator.)
As to why C++ supports the extended range: enum are often used
to define bit masks:
enum X
{
a = 0x01,
b = 0x02,
c = 0x04,
all = a | b | c,
none = 0
};
X operator|( X lhs, X rhs )
{
return X((int)lhs | (int)rhs);
}
// similarly, &, |= and &=, and maybe ~
One could argue that this use would be better handled by
a class, but the use of enum for it is ubiquitous.
(FWIW: my code generator will not generate the ++, -- and
the iterators if any of the enum values has an explicitly
defined value, and will not generate |, & etc. unless all of
the values have explicitly defined values.)
As to why there is no error when you convert some value outside
the legal range (e.g. 100, for X, above) is simply in keeping
with the general philosophy inherited from C: it's better to be
fast than to be correct. Doing extra range checking would
entail additional runtime cost.
Finally with regards to your last example: I don't see this as
a realistic use of enum. The correct solution here is an
int[]. While the C++ enum is rather a mixed breed, I would
only use it as a real enumerated type, or for bit masks (and
only for bit masks because it is such a widely established
idiom).
You can use a switch:
class Invalid {};
Prime& operator ++(Prime& p)
{
switch(p)
{
case n00: return n01;
case n01: return n02;
case n02: return n03;
case n03: return n04;
case n04: return n05;
case n05: return n06;
case n06: return n07;
case n07: return n08;
case n08: return n09;
case n09: return n10;
case n10: return n11;
case n11: return n12;
case n12: return n13;
case n13: return n14;
case n14: return n15;
// Here: 2 choices: loop or throw (which is the only way to signal an error here)
case n15: default: throw Invalid();
}
}
But note that this is not the right use of enums. I personally find this error-prone. If you want to enumerate integers, you can use an array of ints to do this, or for the case of prime numbers, a function (in mathematical sense: int nextPrime(int)).

Restoring any type

are there any ways to restore type of packed into boost::any object? If now, can I store some association map for it? I need something like (pseudocode):
map<key, any> someMap;
someMap["Key"] = some own object;
getType("Key");
Not arbitrarily, you need to have some static type(s) you want to work with in C++.
So you can test for or cast to a specific type using any::type() and any_cast(), e.g.:
const boost::any& any = someMap["Key"].type();
if (int* i = boost::any_cast<int>(&any)) {
std::cout << *i << std::endl;
} else if (double* d = boost::any_cast<double>(&any)) {
// ...
But something like the following can not be done in general due to C++ being statically typed:
magically_restore_type(someMap["Key"]).someMethod();
Using something like boost::any in C++ is almost always not a good idea, exactly because handling arbitrary types is no fun. If you only need to handle a known finite set of types, don't use boost::any - there are better options like boost::variant or polymorphic classes.
Are you trying to get the type of the value, or just cast it back to what it was? If you just want to cast it, just use boost::any_cast:
boost::any val = someMap["Key"];
RealType* r = boost::any_cast<RealType>(&val);
Let's say you did have such a function to extract the correctly-typed extraction from a boost::any. What would the return value of this function be? What would your code look like?
// Extracts v and returns the correct type... except we can't do that in C++. Let's just call it MagicalValue for now.
MagicalValue magic(const boost::any& v);
void perform_magic(const boost::any& v)
{
MagicalValue r = magic(v);
r.hello_world(); // Wait, what?
}
You can't do this type of trickery in statically-typed languages. What you can try is polymorphism instead of boost::any. This gives you a common interface you CAN use in C++.