Setting value to enum - c++

I'm a beginner in C++ so I'm sorry if this is super obvious, but I have an issue with assigning values to an enum. I've declared the enum like so in a header file:
enum face
{ paramControlHeight = 40,
paramLabelWidth = 80,
paramSliderWidth = 300
};
And tried assigning an integer. Needless to say it doesn't work:
paramControlHeight = 40;//Not assignable
After googling about for a while, I tried:
using type_of_p=decltype(paramControlHeight);
Which as I understand, should yield the type of paramControlHeight, and enable me to use
paramControlHeight=static_cast<type_of_p> (40);
But I get the same "un-assignable" error
If anyone could point me in the right direction I'd be very grateful

I want to assign "paramControlHeight" which is inside my enum a different value. So, for example, it starts out as 40, but I would like to change it to 80 later on
You seem to misunderstand what enums are. You seem to expect the enum to behave like this
struct face
{ int paramControlHeight = 40;
int paramLabelWidth = 80;
int paramSliderWidth = 300;
};
face f; // create instance
f.paramControlHeight = 40; // modify member
However, an enum is rather like a
struct face
{
static const int paramControlHeight = 40;
static const int paramLabelWidth = 80;
static const int paramSliderWidth = 300;
};
Now back to your actual enum:
enum face
{ paramControlHeight = 40,
paramLabelWidth = 80,
paramSliderWidth = 300
};
Here paramControlHeight is an enumerator with the value 40. You cannot modify it. It is not meant to be modified. It is meant to enumerate. What you can do is:
face f{ paramControlHeight }; // create instance of face
f = paramSliderWidth; // assign a different value to it
A more typical enum would be
enum face_parts {
nose = 1,
eye = 2,
mouth = 3
};
That you could use like this
void print_face_part( face_parts fp ){
if (fp == nose) std::cout << "nose";
if (fp == eye) std::cout << "eye";
if (fp == mouth) std::cout << "mouth";
}
In simple terms an enum lets you name and group constants. Note that since C++11 there are scoped enums that are more flexible and dont introduce the name of the enumerators in the enclosing namespace.

paramControlHeight, paramLabelWidth, paramSliderWidth are the values. You can't assign anything to them more than you can assign a value to 42.

Related

Unexpected errors regarding structs and arrays

So I'm following a certain tutorial series and trying to use that knowledge to put my own spin on something kindof both similar but also different to the series itself. In one section, to tackle a certain inconvenience which is not important for the scope of my issue, a possible solution was to store certain chunk of data into members of a struct and then call that struct onto a function that later output the data precisely the way we wanted - as an array.
All was well and good, until the function for some reason refused to take in values of the array, claiming there was an overload of information in the array arguments (I will specify the errors later), and that the entity I am returning does not match the function's return type.
Here's my code:
struct TriCoord
{
float Position[3];
int Label[2];
};
std::array<TriCoord, 3> Implement(float x, float y, float z, int j) //2
{
float size = 1.0f;
TriCoord f0;
f0.Position = { x, y, z }; //1
f0.Label = { j, 1 }; //1
TriCoord f1;
f1.Position = { x + 0.5, y + 0.5, z };
f1.Label = { j, 2 };
TriCoord f2;
f2.Position = { x + 0.5, y, z };
f2.Label = { j, 3 };
return { f0, f1, f2 }; //2
};
int main()
{
int X;
float A[3] = Implement(3, 4, 5, 1); //3
std::cout << A[0] << ", " << A[1] << ", " << A[2] << std::endl;
std::cout << "Press Enter key to return" << std::endl;
std::cin >> X;
return 0;
}
I've put comments locating specifically where the errors are.
1) The compiler says that f0 is "not a modifiable lvalue". I see no reason why it shouldn't be. In the array argument at specifically the second element of the array (in this case y), the compiler says that I am adding "too many initializer values". Again, makes no sense. I specified the Position array to have 3 elements and am plugging 3 elements of matching type (float).
These two errors extend to f0.Label, as well as the other TriCoords.
2) The compiler says that the function "returns incomplete type 'std::array'". Furthermore, in the return line, "list-initialization of an object type 'std::array' is not allowed because the type is incomplete".
Technically what I am returning is an std array whose elements are TriCoords and of amount 3, so I don't see the problem once again. I did work around this issue by changing the function's return type to float, but in its stead the return line generates the same error for the second element (in this case f1) as in problem 1.
3) "Initialization with '{...}' expected for aggregate object" I have no idea what this means. I get this error regardless of which return type I specify for my function.
I must emphasise that both me and the series I'm following are using Visual Studios and no such errors popped up in the video I was following. I even copy-pasted the entirety of the video's code line by line and the errors still persisted, leading me to the conclusion that there is something wrong in the way Visual Studios is configured on my end, possibly due to version differences (the video was uploaded this year so it's not running on too old of a version). All my dependencies are correct as well and are present in their respective project-based directories, I have double checked those.
Lastly, the code I used above was a separate testing code I redid on a new project in an attempt to isolate the error. Needless to say, I got the same error in both cases indicating there's nothing inherently wrong with the custom-defined headers and libraries of my original project.
1) You cannot assign into arrays like this once they are initialized.
int arr[3] = {1, 2, 3}; //valid
int arr2[3];
arr2 = {1, 2, 3}; //invalid
In your case, what you could do is instead of: -
TriCoord f0;
f0.Position = { x, y, z };
f0.Label = { j, 1 };
write: -
float tempFloat[3] = { x, y, z };
int tempInt[2] = { j, 1 };
TriCoord f0;
for (int i = 0; i < 3; ++i)
f0.Position[i] = tempFloat[i];
for (int i = 0; i < 2; ++i)
f0.Label[i] = tempInt[i];
2) Solve 1 to solve 2...
3) You are trying to assign std::array<TriCoord, 3> to a float array which is certainly not possible...
At this point, I would strongly advise you to use std::array everywhere.

Displaying element from pointer struct

I have run onto a little problem and I have looked everywhere but I believe I am looking in the wrong direction. I created an account here in hopes of solving a slight issue I have. I am in the middle of programming an RPG and when I attempt to display one characters "magic spells", I can only display [3]. [0] [1] [2] crashes my game. Game is in C++.
Example of my code below:
Create my struct:
struct Fighter {
int HP; //max 999
int maxHP;
int MP; //max 999
int maxMP;
int STR; //max 255
int CON; //max 255
int AGL; //max 100
bool dead;
const char* Magic[];
};
Fighter * player = new Fighter[5];
Initializing and assigning elements with these parameters for 4 party members:
void InitPlayer(int pClass, int p)
{
if(pClass == 0) //Knight
{
player[p].maxHP = 750;
player[p].HP = player[p].maxHP;
player[p].maxMP = 0;
player[p].MP = player[p].maxMP;
player[p].STR = 200;
player[p].CON = 0;
player[p].AGL = 35;
}
else if(pClass == 1) //Ninja
{
player[p].maxHP = 675;
player[p].HP = player[p].maxHP;
player[p].maxMP = 0;
player[p].MP = player[p].maxMP;
player[p].STR = 175;
player[p].CON = 0;
player[p].AGL = 80;
player[p].Magic[0] = "Cure";
player[p].Magic[1] = "Haste";
player[p].Magic[2] = "Sleep";
}
//... More Character code
}
Here I draw/print "Magic" to the screen:
Printf_xy(123,223,player[0].Magic[0]); //Crash
Printf_xy(123,233,player[1].Magic[0]); //Crash
Printf_xy(123,243,player[2].Magic[0]); //Crash
Printf_xy(123,253,player[3].Magic[0]); //Prints "Cure" does not crash
As you can see, it will work but only if I display player[3]. I am sure I am forgetting to do something or initializing something incorrectly. Any help would be greatly appreciated.
Magic is a zero length array - when you assign anything into it, or even try to access Magic[0] you are accessing outside of the array boundaries.
If you know the maximum number of magic entries you need, use that as your array size, something like:
const int MagicLimit = 10
...
const char* Magic[MagicLimit];
Better still, if you are using c++, use a std::vector to hold the magic strings (also use std::string), that way you can easily tell the length of the list.
For example:
std::vector<std::string> Magic;

Initializing typedef struct from C library properly in C++

I want to include a library in my C++ project (controls RGB LED strips on the Raspberry Pi).
Importing the library is working fine but I have quite the issue with properly initializing some structs. I'm pretty lost where to even find the proper syntax, I did a lot of googling but didn't get very far.
What I want to at first is getting the sample application going that comes with the library. See: https://github.com/richardghirst/rpi_ws281x/blob/master/main.c
My main issue is this. How do I do what is done below the C++ way?
ws2811_t ledstring =
{
.freq = TARGET_FREQ,
.dmanum = DMA,
.channel =
{
[0] =
{
.gpionum = GPIO_PIN,
.count = LED_COUNT,
.invert = 0,
.brightness = 255,
},
[1] =
{
.gpionum = 0,
.count = 0,
.invert = 0,
.brightness = 0,
},
},
};
The way this is initialized is C specific and doesn't compile in any current C++ standard. See: Why does C++11 not support designated initializer list as C99?
So far I only ever used my own structs and also never used typedef, so I'm just confused the way structs are defined here.
The struct(s) that gets initialized above is defined in this way. See: https://github.com/richardghirst/rpi_ws281x/blob/master/ws2811.h
typedef struct
{
int gpionum; //< GPIO Pin with PWM alternate function
int invert; //< Invert output signal
int count; //< Number of LEDs, 0 if channel is unused
int brightness; //< Brightness value between 0 and 255
ws2811_led_t *leds; //< LED buffers, allocated by driver based on count
} ws2811_channel_t;
typedef struct
{
struct ws2811_device *device; //< Private data for driver use
uint32_t freq; //< Required output frequency
int dmanum; //< DMA number _not_ already in use
ws2811_channel_t channel[RPI_PWM_CHANNELS];
} ws2811_t;
What I tried was this:
ws2811_led_t matrix[WIDTH][HEIGHT];
ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};
That compiles but results in a malloc error when I come to actually "render" to the LED strip:
int x, y;
for (x = 0; x < WIDTH; x++)
{
for (y = 0; y < HEIGHT; y++)
{
cout << "LEDs size: " << (y * WIDTH) + x << endl;
ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];
}
}
Results in this error message after the loop construct finishes:
malloc(): memory corruption (fast): 0x021acaa8
You should be able to use use following initializer:
ws2811_t ledstring =
{
nullptr,
TARGET_FREQ,
DMA,
{
{ GPIO_PIN, 0, LED_COUNT, 255 },
{ 0 }
}
};
This line
ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];
is almost certainly the cause of the memory corruption, as that can only happen by either a buffer overrun or dereferencing an invalid (but non-NULL) pointer.
I see some problems in this code
ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};
First, in the initializer for channel0 you are setting the leds field to the contents of matrix[0][0] rather than its address. You need to change the final initializer to be simply matrix.
Next, you are initializing channel0.leds to point to the two dimensional array matrix, but treating it as a single dimensional array in ledstring.channel[0].leds[(y * WIDTH) + x]. This should probably be ledstring.channel[0].leds[x][y].
Finally, the last initializer for ledstring should probably be {channel0} for clarity. That's not a big issue, but it allows you to initialize more than one entry in the array.

Is a compile-time checked string-to-int map possible?

I'm probably trying to achieve the impossible, but StackExchange always surprises me, so please have a go at this:
I need to map a name to an integer. The names (about 2k) are unique. There will be no additions nor deletions to that list and the values won't change during runtime.
Implementing them as const int variables gives me compile-time checks for existence and type.
Also this is very clear and verbose in code. Errors are easily spotted.
Implementing them as std::map<std::string, int> gives me a lot of flexibility for building the names to look up with string manipulation. I may use this to give strings as parameters to functions which than can query the list for multiple values by appending pre-/suffixes to that string. I can also loop over several values by creating a numeral part of the key name from the loop variable.
Now my question is: is there a method to combine both advantages? The missing compile-time check (especially for key-existence) almost kills the second method for me. (Especially as std::map silently returns 0 if the key doesn't exist which creates hard to find bugs.) But the looping and pre-/suffix adding capabilities are so damn useful.
I would prefer a solution that doesn't use any additional libraries like boost, but please suggest them nevertheless as I might be able to re-implement them anyway.
An example on what I do with the map:
void init(std::map<std::string, int> &labels)
{
labels.insert(std::make_pair("Bob1" , 45 ));
labels.insert(std::make_pair("Bob2" , 8758 ));
labels.insert(std::make_pair("Bob3" , 436 ));
labels.insert(std::make_pair("Alice_first" , 9224 ));
labels.insert(std::make_pair("Alice_last" , 3510 ));
}
int main()
{
std::map<std::string, int> labels;
init(labels);
for (int i=1; i<=3; i++)
{
std::stringstream key;
key << "Bob" << i;
doSomething(labels[key.str()]);
}
checkName("Alice");
}
void checkName(std::string name)
{
std::stringstream key1,key2;
key1 << name << "_first";
key2 << name << "_last";
doFirstToLast(labels[key1.str()], labels[key2.str()]);
}
Another goal is that the code shown in the main() routine stays as easy and verbose as possible. (Needs to be understood by non-programmers.) The init() function will be code-generated by some tools. The doSomething(int) functions are fixed, but I can write wrapper functions around them. Helpers like checkName() can be more complicated, but need to be easily debuggable.
One way to implement your example is using an enum and token pasting, like this
enum {
Bob1 = 45,
Bob2 = 8758,
Bob3 = 436,
Alice_first = 9224,
Alice_last = 3510
};
#define LABEL( a, b ) ( a ## b )
int main()
{
doSomething( LABEL(Bob,1) );
doSomething( LABEL(Bob,2) );
doSomething( LABEL(Bob,3) );
}
void checkName()
{
doFirstToLast( LABEL(Alice,_first), LABEL(Alice,_last) );
}
Whether or not this is best depends on where the names come from.
If you need to support the for loop use-case, then consider
int bob[] = { 0, Bob1, Bob2, Bob3 }; // Values from the enum
int main()
{
for( int i = 1; i <= 3; i++ ) {
doSomething( bob[i] );
}
}
I'm not sure I understand all your requirements, but how about something like this, without using std::map.
I am assuming that you have three strings, "FIRST", "SECOND" and "THIRD" that you
want to map to 42, 17 and 37, respectively.
#include <stdio.h>
const int m_FIRST = 0;
const int m_SECOND = 1;
const int m_THIRD = 2;
const int map[] = {42, 17, 37};
#define LOOKUP(s) (map[m_ ## s])
int main ()
{
printf("%d\n", LOOKUP(FIRST));
printf("%d\n", LOOKUP(SECOND));
return 0;
}
The disadvantage is that you cannot use variable strings with LOOKUP. But now you can iterate over the values.
Maybe something like this (untested)?
struct Bob {
static constexpr int values[3] = { 45, 8758, 436 };
};
struct Alice {
struct first {
static const int value = 9224;
};
struct last {
static const int value = 3510;
};
};
template <typename NAME>
void checkName()
{
doFirstToLast(NAME::first::value, NAME::last::value);
}
...
constexpr int Bob::values[3]; // need a definition in exactly one TU
int main()
{
for (int i=1; i<=3; i++)
{
doSomething(Bob::values[i]);
}
checkName<Alice>();
}
Using enum you have both compile-time check and you can loop over it:
How can I iterate over an enum?

How to get next value of enum

I have the following problem:
enum Language { English, French, German, Italian, Spanish };
int main() {
Language tongue = German;
tongue = static_cast<Language>(tongue + 1);
cout << tongue;
}
//it returns 3.....but i want to get the language name on index 3.....
I find that an explicit look up table works best, for both converting from enum to text and text to enum:
enum Language_Enum
{
LANGUAGE_FIRST = 0,
LANGUAGE_GERMAN = LANGUAGE_FIRST,
LANGUAGE_ENGLISH,
LANGUAGE_HOPI,
LANGUAGE_WELSH,
LANGUAGE_TEXAN,
LANGUAGE_DUTCH,
LANGUAGE_LAST
};
struct Language_Entry
{
Language_Enum id;
const char * text;
};
const Language Entry language_table[] =
{
{LANGUAGE_GERMAN, "German"},
{LANGUAGE_HOPI, "Hopi"},
{LANGUAGE_DUTCH, "Dutch"},
// ...
};
const unsigned int language_table_size =
sizeof(language_table) / sizeof(language_table[0]);
Specifying the enum along with the text, allows for the enum order to change with minimal effect to the search engine.
The LANGUAGE_FIRST and LANGUAGE_LAST identifiers allow for iteration of the enum:
Language_Enum l;
for (l = LANGUAGE_FIRST; l < LANGUAGE_LAST; ++l)
{
// ...
}
You'll have to create an array of strings which matches your enum e.g.
std::string[] LangTxt = { "English", "French", "German", "Italian", "Spanish" };
then you can reference them as follows:
cout << LangTxt[tongue];
Be careful to keep the definitions together though so they are updated side by side.
It is not so simple to print the enum name for a given enum value in C++. Instead, you can use a map or string array to hold the values, which do allow you to get both the index and the string value.
Best Way to use enum is first give initial value to your enum.
enum TestEnum
{
Zero=0,
One,
Two
}
Even you wont specify anything the default starting index is zero.
To get the value at a particular index simple do that
TestEnum(index);