Use initializer list to initialize new vector - c++
So I have this big map of vectors, you can see I use an initializer list to initialize the vectors.
However, although this works it really doesn't seem like it should, if you create an empty vector and try to use the = operator and then assign it to an initializer list you get the error "too many values in initializer list" but for some reason when you try to do the same with a map of vectors it just... works. However the issue is of course these are allocated on the stack and quickly causes a stack overflow so the goal would be to find a way to use initializer list (or something of similar brevity) to initialize these vectors on the heap.
Example code causing stack over flow below
#include <map>
#include <vector>
#include <string>
struct IVector2 {
int x;
int y;
};
struct animation_frame_t {
IVector2 position;
IVector2 size;
};
std::map<std::string, std::vector<animation_frame_t>> animations;
void initAnimations() {
animations["boss_andromeda_attack_"] = { {{303,101},{100,100}}, {{606,101},{100,100}}, {{606,0},{100,100}}, {{505,909},{100,100}}, {{505,808},{100,100}}, {{505,707},{100,100}}, {{505,606},{100,100}}, {{505,505},{100,100}}, {{505,404},{100,100}}, {{505,303},{100,100}}, {{505,202},{100,100}}, {{505,101},{100,100}}, {{505,0},{100,100}}, {{404,909},{100,100}}, {{404,808},{100,100}}, {{404,707},{100,100}}, {{404,606},{100,100}}, {{404,505},{100,100}}, {{404,404},{100,100}}, {{404,303},{100,100}}, {{404,202},{100,100}}, {{404,101},{100,100}}, {{404,0},{100,100}} };
animations["boss_andromeda_breathing_"] = { {{303,909},{100,100}}, {{303,808},{100,100}}, {{303,707},{100,100}}, {{303,606},{100,100}}, {{303,505},{100,100}}, {{303,505},{100,100}}, {{303,404},{100,100}}, {{303,303},{100,100}}, {{303,202},{100,100}}, {{606,202},{100,100}} };
animations["boss_andromeda_death_"] = { {{303,0},{100,100}}, {{202,909},{100,100}}, {{202,808},{100,100}}, {{202,707},{100,100}}, {{202,606},{100,100}}, {{202,505},{100,100}}, {{202,404},{100,100}}, {{202,303},{100,100}}, {{202,202},{100,100}}, {{202,101},{100,100}}, {{202,0},{100,100}}, {{101,909},{100,100}}, {{101,808},{100,100}} };
animations["boss_andromeda_hit_"] = { {{303,0},{100,100}}, {{202,909},{100,100}}, {{202,808},{100,100}} };
animations["boss_andromeda_idle_"] = { {{101,707},{100,100}}, {{101,606},{100,100}}, {{101,505},{100,100}}, {{101,404},{100,100}}, {{101,303},{100,100}}, {{101,202},{100,100}}, {{101,101},{100,100}}, {{101,0},{100,100}}, {{0,909},{100,100}}, {{0,808},{100,100}} };
animations["boss_andromeda_run_"] = { {{0,707},{100,100}}, {{0,606},{100,100}}, {{0,505},{100,100}}, {{0,404},{100,100}}, {{0,303},{100,100}}, {{0,202},{100,100}}, {{0,101},{100,100}}, {{0,0},{100,100}} };
animations["boss_antiswarm_attack_"] = { {{393,1310},{130,130}}, {{917,655},{130,130}}, {{917,524},{130,130}}, {{917,393},{130,130}}, {{917,262},{130,130}}, {{917,131},{130,130}}, {{917,0},{130,130}}, {{786,1834},{130,130}}, {{786,1703},{130,130}}, {{786,1572},{130,130}}, {{786,1441},{130,130}}, {{786,1310},{130,130}}, {{786,1179},{130,130}}, {{786,1048},{130,130}}, {{786,917},{130,130}}, {{786,786},{130,130}}, {{786,655},{130,130}}, {{786,524},{130,130}}, {{786,393},{130,130}}, {{786,262},{130,130}}, {{786,131},{130,130}}, {{786,0},{130,130}}, {{655,1834},{130,130}}, {{655,1703},{130,130}}, {{655,1572},{130,130}}, {{655,1441},{130,130}}, {{655,1310},{130,130}}, {{655,1179},{130,130}}, {{655,1048},{130,130}}, {{655,917},{130,130}}, {{655,786},{130,130}}, {{655,655},{130,130}}, {{655,524},{130,130}}, {{655,393},{130,130}}, {{655,262},{130,130}}, {{655,131},{130,130}}, {{655,0},{130,130}}, {{524,1834},{130,130}}, {{524,1703},{130,130}}, {{524,1572},{130,130}}, {{524,1441},{130,130}}, {{524,1310},{130,130}}, {{524,1179},{130,130}} };
animations["boss_antiswarm_breathing_"] = { {{524,1048},{130,130}}, {{524,917},{130,130}}, {{524,786},{130,130}}, {{524,655},{130,130}}, {{524,524},{130,130}}, {{524,393},{130,130}}, {{524,262},{130,130}}, {{524,131},{130,130}}, {{524,0},{130,130}}, {{393,1834},{130,130}}, {{393,1703},{130,130}}, {{393,1572},{130,130}}, {{393,1441},{130,130}}, {{917,786},{130,130}} };
animations["boss_antiswarm_death_"] = { {{393,1179},{130,130}}, {{393,1048},{130,130}}, {{393,917},{130,130}}, {{393,786},{130,130}}, {{393,655},{130,130}}, {{393,524},{130,130}}, {{393,393},{130,130}}, {{393,262},{130,130}}, {{393,131},{130,130}}, {{393,0},{130,130}}, {{262,1834},{130,130}}, {{262,1703},{130,130}}, {{262,1572},{130,130}}, {{262,1441},{130,130}}, {{262,1310},{130,130}}, {{262,1179},{130,130}}, {{262,1048},{130,130}}, {{262,917},{130,130}}, {{262,786},{130,130}}, {{262,655},{130,130}}, {{262,524},{130,130}}, {{262,393},{130,130}}, {{262,262},{130,130}}, {{262,131},{130,130}}, {{262,0},{130,130}}, {{131,1834},{130,130}}, {{131,1703},{130,130}} };
animations["boss_antiswarm_hit_"] = { {{131,1572},{130,130}}, {{131,1441},{130,130}}, {{131,1310},{130,130}} };
//40k more lines of code
Related
How to programmatically assign class/struct attributes?
I am attempting to translate my Python program to C++, but because I am new to C++ I am encountering some problems. The input file is first parsed (works, not shown) to create the INITIAL_VALUES dict/map, which I then want to use to assign the Parameters class/struct attributes using the DEST_DICT_PARAMS dict/map. I was able to achieve this in Python code with: import dataclasses INITIAL_VALUES = { "BULK": { "MAGMA": { "M0": 1.0, "T0": 1320.0, }, "ASSIM": { "M0": 0.0, "T0": 600.0, }, } } DEST_DICT_PARAMS = { 'M0': {"MAGMA": 'Mm0', "ASSIM": 'Ma0'}, 'T0': {"MAGMA": 'Tm0', "ASSIM": 'Ta0'}, } #dataclasses.dataclass class Parameters: Mm0: float = None Ma0: float = None Ta0: float = None Tm0: float = None class ParametersReader: def __init__(self): self.parameters = Parameters() self._assignParameters() def _assignParameters(self): for param_fam, dest in DEST_DICT_PARAMS.items(): for component, param in dest.items(): value = INITIAL_VALUES["BULK"][component][param_fam] setattr(self.parameters, param, value) params = ParametersReader() print(params.parameters) Output: Parameters(Mm0=1.0, Ma0=0.0, Ta0=600.0, Tm0=1320.0) So I wrote the corresponding C++ code: #include <iostream> #include <map> using std::map; using std::string; map<string, map<string, map<string, float> > > INITIAL_VALUES = {{ "BULK", { {"MAGMA", { {"M0", 1.0}, {"T0", 1320.0}, }}, {"ASSIM", { {"M0", 0.0}, {"T0", 600.0}, }}, } }}; map<string, map<string, string> > DEST_DICT_PARAMS = {{ {"M0", {{"MAGMA", "Mm0"}, {"ASSIM", "Ma0"}}}, {"T0", {{"MAGMA", "Tm0"}, {"ASSIM", "Ta0"}}}, }}; struct Parameters { float Mm0; float Ma0; float Ta0; float Tm0; } parameters; class ParametersReader { public: void assignParameters_() { map<string, map<string, string> >::iterator itr0; map<string, string>::iterator itr1; for (itr0 = DEST_DICT_PARAMS.begin(); itr0 != DEST_DICT_PARAMS.end(); itr0++) { for (itr1 = itr0->second.begin(); itr1 != itr0->second.end(); itr1++) { parameters.itr1->second = INITIAL_VALUES["BULK"][itr1->first]; } } } }; int main() { ParametersReader params; params.assignParameters_(); } But I'm getting an error at the line parameters.itr1->second = INITIAL_VALUES['BULK'][itr1->first] saying "no member named 'itr1' in 'Parameters'". That error makes total sense because the code is literally trying to interpret 'itr1' as an attribute name and not the whole 'itr1->second' as the name. I think this comes down to the fact that I can't seem to find a C++ equivalent to Python's setattr(obj, name, val) function that takes an object and its attribute name and assigns it a value. Is there a C++ solution to what I am attempting? Perhaps my entire approach is incompatible with C++. If so, would you kindly suggest an alternative approach? I would like to keep the input file format the same between the Python and C++ versions.
C++ does not have runtime reflection like Python. You cannot look up a class member by name using a runtime string because class member names do not exist at runtime. What you can do is look up a class member via a pointer to member. This is an offset into the object calculated at compile time by the compiler: std::map<std::string, std::map<std::string, float Parameters::*> > DEST_DICT_PARAMS = {{ {"M0", {{"MAGMA", &Parameters::Mm0}, {"ASSIM", &Parameters::Ma0}}}, {"T0", {{"MAGMA", &Parameters::Tm0}, {"ASSIM", &Parameters::Ta0}}}, }}; class ParametersReader { public: void assignParameters_() { for (auto& [param_fam, dest] : DEST_DICT_PARAMS) { for (auto& [component, param] : dest) { parameters.*param = INITIAL_VALUES["BULK"][component][param_fam]; } } } }; Demo Note I've also used range-based for loops and structured bindings to clean up your assignParameters_ function.
C++ has no equivalent to Pythons setattr(self.parameters, param, value). If you want to have a mapping between strings and members you need to write it yourself. You can use pointers to members to do something along the line of: #include <map> #include <iostream> struct foo { float a = 0.0f; float b = 0.0f; }; // list all members and their string represenation std::map<std::string,float foo::*> mmap { { "a", &foo::a }, { "b", &foo::b } }; int main() { foo f; std::map<std::string,float> values { {"a", 0.1}, {"b", 0.2} }; for (const auto& val : values) { // lookup the member pointers via the strings from mmap // use the found function pointer to assing to corresponding member in f f.*mmap[val.first] = val.second; } std::cout << f.a << " " << f.b << "\n"; } Note that the code assumes that all strings present in values are also present in mmap. If not, it will fail horribly. To fix that mmap.find should be used instead and the case of not found string handleted appropriately. This works, though there is no way to get that mapping implicitly from the class definition only. On the other, hand I can imagine libraries to exist that can help with that.
Having trouble initiating an array in a structure
class CRA_Account { int tax[4]; double refund[4]; int SIN; public: CRA_Account(); } CRA_Account::CRA_Account() { SIN = 0; tax[4] = { 0 }; refund[4] = { 0 }; } When I create a object in main it'll set the SIN to 0 but won't do the same to the arrays. Can someone help why?
tax[4] = { 0 }; is wrong at many levels.. One way to initlizie your class: CRA_Account::CRA_Account(): tax{0,0,0,0}, refund{0,0,0,0}, SIN{0}{ } Online Try to have a look at std::array
What to use for initial values? Struct, enum or class, #defines c++
It's kind of a shame to ask this question and probably will fit better in the Code Review site, so sorry in advance. My question is the following (can be extensible for other languages since is more OOP): I have a class: class Unit { public: Unit(Type); Type type; private: int weaponry; int shielding; int hull; int rapid_fire; } with an enum to differenciate between different types of units. enum Type{ Cruiser, Missile }; All the units will be initialize with a default value (plus a factor, depending in external variable). Unit::Unit(Type type) { this->type = type; int weaponry, shielding, hull,rapid_fire; switch(type){ case Cruiser: weaponry = 2700; shielding = 50; hull = 400; rapid_fire = 5; break; case Missile: weaponry = 200; shielding = 20; hull = 80; rapid_fire = 0; break; } this->weaponry = weaponry ; //+ whatever this->shielding = shielding; //+ whatever this->hull = hull; //+ whatever this->rapid_fire = rapid_fire; } I will also have a method that will change the values of the object, such as the typical setHull(int newHull){this->hull = newHull} In one of these methods, i want to revert one of the private variables to its default value, in the example case, if is Cruiser this->shielding = 50, if its a missile = 20. My questions are the following. Am i doing something wrong? I have several options to keep the defaults values, either with (the one I would "noobly" will choose) #define initial_cruiser_shielding 50 either with enum: enum shielding_init{ cruiser_i = 50, missile_i = 20 }; to have default instances of the basic objects, and then just copy them and create as many new objects I need. Thanks in advance!
My recommendation will be to create private static member functions that can return default values. class Unit { public: Unit(Type); Type type; int set_default_weaponry() { weaponry = get_default_weaponry(); } int set_default_shielding() { shielding = get_default_shielding(); } int set_default_hull() { hull = get_default_hull(); } int set_default_rapid_fire() { rapid_fire = get_default_rapid_fire(); } private: int weaponry; int shielding; int hull; int rapid_fire; static int get_default_weaponry(); static int get_default_shielding(); static int get_default_hull(); static int get_default_rapid_fire(); }
Copy Dynamic Struct Array into another C++
I'm not that good in English, that's why my Question is probably wrong. But I have a problem and I don't know how to solve it or if it's even possible to do. I have 2 Structs defined: typedef struct { UINT16 ScriptNumber; std::string ScriptText; } StepStruct; typedef struct { std::string SequenceName; std::string DisplayName; StepStruct SequenceSteps; } SequenceStruct; As you can see, the first Struct is a Member of the second struct. So I want both structs to by dynamical. So I created 2 Dynamic Arrays from the Type StepStruct and 1 dynamic Array from the Type SequenceStruct. The two dynamical Arrays for of the Type StepStructs are defined as follows: StepStruct gsFirstSkript[] = { { 1 , "SkriptText One"}, { 2 , "SkriptText Two"}, { 45, "SkriptText Three"} } StepStruct gsSecondSkript[] = { { 48, "SkriptText One"}, { 2 , "SkriptText Two"}, { 45, "SkriptText Three"} } Those to Structs are of the Type StepStruct. Now I want to do the Same with a SequenceStruct Type, but I want to assign the two Arrays I already have to it under the Struct Member SequenceSteps. I mean this as follows: SequenceStruct gsSequenceList[] = { { "FirstScript", "Test One", gsFirstSkript}, { "SecondScript", "Test Two", gsSecondSkript} } If I now want to Read the Member gsSequenceList, I can not access any information under the SequenceSteps Index of it! What means, that the Data is not copied! I tried it with Pointers but had no success. UINT16 lTestVal = gsSequenceList[0].SequenceSteps[2].ScriptNumber; So Can I mangage that this works, and lTestVal contains the Value 45?
typedef struct { std::string SequenceName; std::string DisplayName; StepStruct* SequenceSteps; } SequenceStruct; This will allow the code to compile and the test fragment you've shown will work. However this will not copy the data. If you change gsFristSkript it will change in gsSequenceList as well. If you want to make a copy of the data you can either do that explicitly, have a constructor or just use vector<>. Here's the solution with vector: #include <vector> ... typedef struct{ std::string SequenceName; std::string DisplayName; vector<StepStruct> SequenceSteps; } SequenceStruct; vector<StepStruct> gsFirstSkript = { { 1 , "SkriptText One"}, { 2 , "SkriptText Two"}, { 45, "SkriptText Three"} } vector<StepStruct> gsSecondSkript = { { 48, "SkriptText One"}, { 2 , "SkriptText Two"}, { 45, "SkriptText Three"} } SequenceStruct gsSequenceList[] = { { "FirstScript", "Test One", gsFirstSkript}, { "SecondScript", "Test Two", gsSecondSkript} }
C++ Minecraft2D Block Type?
I was working on a Minecraft2D kind of game in Java and I decided to create the same game in C++ to enhance my C++ abilities. But I have a problem. I had a BlockType enum in Java which contained that BlockType's image location and hardness (how long it takes to mine it). I figured out that in C++ enums are different than the ones in Java. How can I implement this in C++? BlockType.java: public enum BlockType { STONE("res/blocks/stone.png",3), COAL("res/blocks/coal.png", 2), AIR("res/blocks/air.png",0), GRASS("res/blocks/grass.png",1), DIRT("res/blocks/dirt.png",1), DIAMOND("res/blocks/diamond.png",5), REDSTONE("res/blocks/redstone.png",3), COBBLE("res/blocks/cobble.png",3), BRICK("res/blocks/brick.png",4), IRON("res/blocks/iron.png",4), GOLD("res/blocks/gold.png",5); public final String location; public final int hardness; BlockType(String location, int hardness){ this.location = location; this.hardness = hardness; } }
I'll go with something similar to SingerOfTheFall answer: enum blocks { STONE, COAL, GOLD }; struct BlockType { BlockType(std::string loc, int h): location(loc), hardness(h) {} std::string location; int hardness; }; BlockType blockTypes[] = { BlockType("res/blocks/stone.png", 3), // STONE BlockType("res/blocks/coal.png", 2), // COAL BlockType("res/blocks/gold.png", 5) // GOLD }; // use: cout << "Location: " << blockTypes[STONE].location << endl; std::map is a good container, but it uses binary search every time you need to get the value. Indices will be from 0 to n so you can use array instead.
A possibility would be use a std::map, keyed by an enum value and with a value of std::pair<sd::string, int>: #include <string> #include <map> #include <utility> enum BlockType { STONE, COAL, GOLD }; std::map<BlockType, std::pair<std::string, int>> BlockTypes; BlockTypes[STONE] = std::make_pair(std::string("res/blocks/stone.png"), 3); BlockTypes[COAL] = std::make_pair(std::string("res/blocks/coal.png"), 2); BlockTypes[GOLD] = std::make_pair(std::string("res/blocks/gold.png"), 5);
C++ enums work another way indeed. enum eMyEnum { ONE = 15, TWO = 22 }; is about all you can get from them, basically they just allow you to create 'names' for INT values. For your case, I would make an enum for the block names: enum blocks { STONE, SAND, <...> }; and then make a map: < blocks, pair< string, int > > ^ ^ ^ ^ | | | | | | | hardness | | path to picture | | | the block's attributes: the picture path and hardness | the block type from the enum (e.g. SAND) Or just make a structure to hold three values: struct block { string type;//or int, or your enum type, depending on how do you want to store it. string picture; int hardness; }
I would combine both the answers here and make a mapping of enum to block struct struct Block { block(path, str) : strength(str), path(path) {} int str; std::string path; }; enum BlockType { STONE, COAL, ETC } std::map<BlockType, Block> blocks; blocks[STONE] = Block("c:/block/bla.png", 1); blocks[STONE].str; // 1 blocks[STONE].path; // "c:/block/bla.png"
Why use and std::map whan an array will do? (Which can be initialized at compile time) using namespace std; struct BlockType { enum { STONE = 0, COAL, LAST }; BlockType(string location, int hardness) : location(location), hardness(hardness) {} const string location; const int hardness; static const BlockType Blocks[LAST]; }; const BlockType BlockType::Blocks[] = { BlockType("res/blocks/stone.png", 3), BlockType("res/blocks/coal.png", 2) }; int main() { cout << BlockType::Blocks[BlockType::STONE].location << `\n`; return 0; }