Accessing the values of an enum defined in a struct - c++

The struct is as follows:
struct padData
{
enum buttonsAndAxes
{
select,
start,
ps
};
};
The object of the struct:
padData pad;
I am accessing this enum as follows:
printf ("\n%d", pad.buttonsAndAxes[0]);
Error:
error: invalid use of ‘enum padData::buttonsAndAxes’
Then, I tried:
printf ("\n%d", pad::buttonsAndAxes[0]);
Error:
error: ‘pad’ is not a class or namespace
Now what? Please guide.
Compiler: gcc version 4.5.0
EDIT 1:____________________________________
printf ("\nemit: %d", padData::(select)0);
results in:
error: expected unqualified-id before ‘(’ token
My aim is to fetch the word "select" through its value 0. How to achieve that? Also, is the word "select" a string?

The enum values become names in the scope of the class. So you would use padData::select from outside the class, or just select from inside the class.
In C++11 you can qualify the enumerators with the name of the enum, giving padData::buttonsAndAxes::select from the outside and buttonsAndAxes::select from inside.
Printing the name of an enumerator is not easily done in C++, because the names are gone after compilation. You need to set up a table mapping the values to their strings by hand. If you don't supply explicit values like in your example, you can simply use an array:
enum buttonsAndAxes
{
select,
start,
ps
};
const char* buttonsAndAxesNames[] = {
"select",
"start",
"ps"
};
And then you index into that array:
printf("%s", buttonsAndAxesNames[select]);
If you want some more sophisticated approach, you can find a bunch of tricks in previous questions.

printf ("\n%d", padData::select);
Enum is not array, it is used without index.

ENUMS are mainly used for better readability of code rather than calculation facilitators. ENUMS are mainly literals which are assigned values 0,1,2 etc unless specified otherwise. So you should always use them with "::" qualification rather than as array

You seem to need a good C++ book.
Enumerations, in C and C++, are a convenient way to:
map an integral value to a "smart" name
group together values that belong together
The syntax is quite simple (in C++03):
enum <enum-name> {
<value-name-0> [= <value-0>],
<value-name-1> [= <value-1>],
...
};
Where:
<enum-name> is the name of the type that is introduced
<value-name-X> is the name of a value of the enum
<value-X> is the value given to the name, and is optional
If no value is given to a name:
if it is the first, it is set to 0
else, it is set to the value of the previous name, + 1
Here is a small example demonstrating the use of enums:
enum Color {
Blue,
Green,
Red
};
char const* name(Color c) {
switch(c) {
case Blue: return "Blue";
case Green: return "Green";
case Red: return "Red";
}
assert(0 && "Who stored crap in my enum ?");
}
This illustrates a few important points at once:
Color is a type, like a struct type or a class type. It can be typedefed and all.
an enum "value-name" is an integral constant, it can be used as template parameter or in switch cases.
an enum "value-name" is injected in the scope in which the type is declared, and not nested within. (C++11 allows to scope the values with the enum class syntax)
something else entirely could be stored in the enum, while this should not happen in well behaved applications, you can do it through casting...
What is not shown, is that an enum is under the hood a plain integer. The exact underlying type though is determined at the discretion of the compiler. There are a few rules in this choice, that should not matter to you, all you should know is that the type chosen is wide enough to contain all the values of the enum (and possibly signed if required). What it implies is that the type chosen is not necessarily a plain int.
Therefore: printf("%d", Green); is a programming error. It should be printf("%d", (int)Green);.
Another important point, is that enum names do not appear in the final binary. The names are substituted for their values directly, no runtime overhead at all. Debuggers typically retrieve the names from the debug information (if available) and substitute them back in when presenting the information to you.

Related

returning string_view from function

I am writing a lot of parser code where string_view excels, and have gotten fond of the type. I recently read ArthurO'Dwyer's article std::string_view is a borrow type, where he concludes that string_view (and other 'borrow types') are fine to use as long as they "... appear only as function parameters and for-loop control variables." (with a couple of exceptions).
However, I have lately started to use string_view as return value for functions that convert enum to string (which I use a lot), like this Compiler Explorer:
#include <iostream>
#include <string>
#include <array>
#include <algorithm>
enum class Color
{
red, green, blue, yellow,
last // Must be kept last
};
constexpr std::string_view toString(Color color);
// The rest would normally be in a .cpp file
using cts = std::pair<Color, std::string_view>;
constexpr std::array colorNames = {cts{Color::red, "red color"},
cts{Color::green, "green color"},
cts{Color::blue, "blue color"},
cts{Color::yellow, "yellow color"}};
static_assert(colorNames.size() == static_cast<size_t>(Color::last));
constexpr std::string_view toString(Color color)
{
// Normally calling a library function (which also checks for no match), instead of this:
return std::ranges::find(colorNames, color, &cts::first)->second;
}
int main()
{
auto s1 = toString(Color::green);
auto s2 = toString(Color::blue);
std::cout << s1 << ' ' << s2 << std::endl;
}
The reasons I have for doing it this way are:
By having it stored in an array as string_view, I can make the entire table constexpr.
By returning the string_view directly, there is no need of converting the string representation, so the entire function can be constexpr, or at least avoid creating unnecessary strings even when called with a non-constexpr parameter.
A side effect of having the table constexpr is that I can use static_assert to check that all elements of the enum are in the table, which is really great for catching additions to the enum. I really don't like having to put the 'last' enum value in there, but I don't see a better solution.
So my question is really, is returning the string_view this way unsafe (or UB) in any way, or can I keep on doing this with good conscience?
Alternatively, is there a better (faster/safer) way of solving this general problem of enum-to-string?
Addition: After reading G. Sliepen's very good answer, I'd like to add upon my comment to his answer: I often have the opposite function as well, e.g.:
constexpr Color fromString(string_view str)
{
// No-match handling omitted
return std::ranges::find(colorNames, color, &cts::second)->first;
}
In those situations I really do need the translation as a separate table so that it can be used by both functions. But in many other cases, the function containing a switch statement is the simplest and best.
is returning the string_view this way unsafe (or UB) in any way, or can I keep on doing this with good conscience?
Yes. The way you use it is perfectly ok. The string_view returned by your toString function forms a view on data that will remain intact until the program terminates.
Alternatively, is there a better (faster/safer) way of solving this general problem of enum-to-string?
You could make a constexpr function with a switch-statement inside it, like so:
constexpr std::string_view toString(Color color)
{
switch (color) {
case Color::red: return "red";
case Color::green: return "green";
...
}
}
There should be no difference in efficiency if the function is evaluated at compile-time. But the compiler can check if you added case-statements for all the possible Colors, and if not it will give a warning. There's also no need for a Color::last this way.
Keeping both the enum and the std::array or switch-statement in sync can be annoying, especially if you have lots of enumeration values. X macros might help here.

Is it possible to map a type to an integer?

Consider the following struct:
struct value{
std::vector<UCHAR> raw_data;
int type;
};
Lets say the value of type can be { 0, 1, 2 } for this example.
If type == 0 then the data in the vector is representing a 4byte signed integer
If type == 1 then the data in the vector is representing a 2byte signed integer
If type == 2 then the data in the vector is an array of raw bytes of arbitrary length
The format of the structure is out of my control and there are over 30 possible values of type.
Is it possible to determine the type at runtime? Perhaps something like this pseudo code:
void PrintValue(value & v)
{
TypeLookup<v.type> val(v); // Assuming the type is supported by cout
std::cout << val << std::endl;
}
What I am currently doing is a large switch statment anytime I use value then calling the apropriate conversion method eg:
int32_t GetValAs32Integer();
int16_t GetValAsShort();
std::vector<UCHAR> GetValAsRaw();
Is there a more eligant way to do this?
Is there a more eligant way to do this?
No. A switch over type is as elegant as this gets. And given that you only have to handle 3 values, it should be elegant enough.
No, you can't really do this. There is no "type" variable that allows you to pass a type to a function. However templates give you virtually all the functionality you require, other than the ability to switch on the type of a variable at runtime. You can specialise a template, and you can create "auto" variables which hold any type (but ultimately derived from either templates or types directly aded to sourcecode).
If you find you need dynamic typing in C++, the best answer is to move up a level. Create or get from the web a JSON (Javascript object notation) parser / wrapper, and pass the dynamic variables around in that. Then you can query for fields and for their type, so it's possible to have an "employee" with or without a "title" field, if say customs in one country are different from customs in another and some place omit the "Mr" whilst others insist on it.

Cannot resolve type for template function

I'm trying to code up something very simple in D, but I'm having a few problems with one of the standard library template functions (specifically, nextPermutation from std.algorithm).
The crux of what I'm trying to do is to create all permutations of pandigital numbers (that is, numbers including all the values 1 to 9 exactly once).
To do this, I've done the following:
import std.algorithm;
import std.conv;
int[] pandigitals()
{
char[] initial = "123456789".dup;
auto pan = [to!int(initial)];
while(nextPermutation!(initial)) {
pan ~= to!int(initial);
}
return pan;
}
This gives me the error:
Error: cannot resolve type for nextPermutation!(initial)
I've also tried to explicitly set the types:
while(nextPermutation!("a<b", char[])(initial))
However, this gives an error saying it cannot match the template:
Error: template instance std.algorithm.nextPermutation!("a < b", char[]) does not match template declaration nextPermutation(alias less = "a < b", BidirectionalRange)(ref BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange)
What is the correct form of the call meant to be?
Well, your first problem is that you're passing initial as a template argument instead of a function argument. The !() is for template arguments. so, instead of
while(nextPermutation!(initial))
you need to do
while(nextPermutation(initial)) {
Now, that will still give you an error.
q.d(10): Error: template std.algorithm.nextPermutation cannot deduce function from argument types !()(char[]), candidates are:
/usr/include/D/phobos/std/algorithm.d(12351): std.algorithm.nextPermutation(alias less = "a<b", BidirectionalRange)(ref BidirectionalRange range) if (isBidirectionalRange!BidirectionalRange && hasSwappableElements!BidirectionalRange)
And that's because hasSwappableElements!(char[]) is false, and per nextPermutations' template constraint it needs to be true for a type to work with nextPermutations.
It's false because all strings are treated as ranges of dchar rather than their actual element type. This is because in UTF-8 (char) and UTF-16 (wchar), there are multiple code units per code point, so operating on individual code units could break up a code point, whereas in UTF-32 (dchar), there's always one code unit per code point. Essentially, if arrays of char or wchar were treated as ranges of char or wchar, you'd run a high risk of breaking up characters so that you'd end up with pieces of characters rather than whole characters. So, in general in D, if you want to operate on an individual character, you should use dchar, not char or wchar. If you're not very familiar with Unicode, I'd suggest reading this article by Joel Spoelsky on the subject.
However, regardless of why hasSwappableElements!(char[]) is false, it is false, so you're going to need to use a different type. The simplest thing would probably be to just swap your algorithm over to using dchar[] instead.
int[] pandigitals()
{
dchar[] initial = "123456789"d.dup;
auto pan = [to!int(initial)];
while(nextPermutation(initial)) {
pan ~= to!int(initial);
}
return pan;
}

error when declaring an enum to a variable

I have the following syntax:
enum home
{
no,
yes,
}homew;
home homes;
std::string s;
s="no";
homes=s; //is not working. Why?
Were am I wrong?
You are confusing strings with enumerated values.
An enum variable is simply an integer that you can use a literal for at compile time, nothing more than that.
It makes the code more understandable and self-documenting rather than merely using a number literal.
This
enum home { no, yes, } homew;
defines the type home plus a variable homew of that type.
Did you intent that? Why?
The values defined for an enum type are literals, to be used as such:
home homes = no;
In C++ there's no built-in way to convert between enum value literals and a string representation of them. If you need this, you'll have to cook up your own.
enums in C++ are implicitly an int data type. You can't assign string values to enum.
It doesn't compile because C++ provides no built-in mechanism for converting from std::string to an enum.
typeof(home) != typeof(std::string) // types are not equal
Thus, you cannot assign an enum to std::string or otherwise. Implicit conversion between enum and integral types like bool, int etc. is possible however.
Is there a way I can solve my problem as it is?
If possible use std::map.
std::map<std::string, home> myTypes;
myTypes["yes"] = yes;
myTypes["no"] = no;
Now you can do,
homes = myTypes["no"];
As others pointed out, enums values are of int type. You could instead write a small function that converts from enum to String like this:
std::string GetStringFromEnum(home iHome)
{
switch (home)
{
case yes: return "yes";
case no: return "no"; break;
default: return "here be dragons";
}
}
and vice-versa:
home GetEnumFromString(std::string iImput)
{
if (iImput == "yes") return yes;
return no; //if you extend the enum beyond 2 values, this function will get more complicated
}
and you could modify your code like so:
homes = GetStringFromEnum(no)
the downside for this approach is that if you modify the enum, you must also modify the convert function.
HTH,JP

how to use strcat with an ENUM?

I have an external tool which is generating an ENUM based on user inputs. Now this ENUM is being used by my C++ code where in i have to select a particular ENUM based on a variable say 'x'. The ENUMS generated are of the form 'ENUM_1', 'ENUM_2', 'ENUM_3'....so on. Now I want the code inside my code such that the appropriate ENUM is chosen based on 'x'. I tried using the strcat function like:
typedef enum ( enum_1, enum_2, enum_3...enum_n) map1;
y=(map1)strcat("enum_", x);
but it gives me the error "Cannot convert from char* to map1.
Can someone pls suggest a method of achieving this.
ThankYou
You can't do this using strcat. From the description what I understand is that you want to convert x to map1. To achieve this, you can do map1 m = (map1)(x-1); See this sample code:
typedef enum { enum_1, enum_2, enum_3} map1;
int main()
{
int x = 1;
map1 m = (map1)(x-1);
}
-1 is required because, the integer value of the enums in map1 starts from 0.
You can't do this. Well you can't do it this way...
Enums aren't evaluated by name at compile time. You'll have to try something with the preprocessor. You can create a define to do something similar. Something like:
#define fn(x) enum_##x
And then call
fn(x)
But this happens when the file gets preprocessed. So you can't access runtime variables. Judging by your code I don't think you'll be able to do what you want.
Good luck though.
Now I want the code inside my code such that the appropriate ENUM is chosen based on 'x'.
Enumerated values are constants and based on the statement I assume that x is an integer data type.
y=(map1)strcat("enum_", x);
strcat(..) passing parameters should be of type char*. And clearly x is not of type char* based on previous statement. It not clear why are you using strcat for achieving this task.
Answer for your subject line: No. You cannot use strcat with enumerated values.