I have a struct :
typedef struct
{
int nNum;
string str;
}KeyPair;
Then I initialize my struct into something like this:
KeyPair keys[] =
{
{0, "tester"},
{2, "yadah"},
{0, "tester"}
};
And yet, let's say a number of other initializations:
KeyPair keysA[] =
{
{0, "tester"},
{2, "yadah"},
{0, "tester"}
};
KeyPair keysB[] =
{
{0, "testeras"},
{2, "yadahsdf"},
{3, "testerasss"}
};
KeyPair OtherkeysA[] =
{
{1, "tester"},
{2, "yadah"},
{3, "tester"}
};
and like 20 more of 'em.
Now, how do I create another struct and initialize it such that it contains these initiazed KeyPairs?
The reason for this is because I will repetitively call a function whose parameters would come for these structs. And I DO NOT want to do it this way:
pressKeyPairs( keys, sizeof( keys) / sizeof( keys[0] ) );
pressKeyPairs( keysA, sizeof( keysA) / sizeof( keysA[0] ) );
pressKeyPairs( keysB, sizeof( keysB) / sizeof( keysB[0] ) );
pressKeyPairs( OtherkeysA, sizeof( OtherkeysA) / sizeof( OtherkeysA[0] ) );
and so on...
So I would like to just loop through a struct containing these inilialized instantiations of KeyPairs...
OR I would like to put these initialized instances of KeyPairs into a vector and just loop through the vector... How do I do that?
Assuming that you have a fixed number key pairs, you could use a structure member function:
typedef struct KeyPairs {
KeyPair keysA[3];
KeyPair keysB[3];
KeyPair otherKeysA[3];
void init() {
keysA[0].nNum = 0;
keysA[0].str = "tester";
keysA[1].nNum = 2;
keysA[1].str = "yadah";
keysA[2].nNum = 0;
keysA[2].str = "tester";
// and so on for other keys
}
} KeyPairs;
Then use it like so:
KeyPairs pairs;
pairs.init();
How about doing real C++ and using constructors ?
(note that typedefs are implicits for structs in C++)
struct KeyPair
{
int nNum;
string str;
public:
KeyPair() {}
KeyPair(int n, string s) : nNum(n), str(s) {}
};
And then use another struct :
struct TripleKeyPair
{
KeyPair keys[3];
TripleKeyPair()
{
// Your initialisation code goes here
}
};
And finally, I wouldn't advice using names such as :
KeysA, KeysB, KeysC ...
Arrays are exactly for this. Why note use std::vector ?
How about using "null" objects as delimiters in the array? You would have to use constructors though:
struct KeyPair
{
KeyPair() : fIsEmpty(true) {}
KeyPair(int nNum_, const char *szStr) : nNum(nNum_), str(szStr), fIsEmpty(false) {}
int nNum;
string str;
bool fIsEmpty;
};
Then you can initialize it like this:
KeyPair allKeys[] =
{
KeyPair(0, "testeras"),
KeyPair(2, "yadahsdf"),
KeyPair(3, "testerasss"),
KeyPair(),
KeyPair(0, "tester"),
KeyPair(2, "yadah"),
KeyPair(3, "tester"),
KeyPair(1, "moreyadah"),
KeyPair()
};
And the iteration is trivial if you implement a kind of strlen() analog for KeyPair object array.
Related
I am creating multiple different types of encoders where the main difference is the different data structures used to initialize the class. My header is something like this
struct tagTypeInfo {
uint16_t start;
uint16_t last;
uint16_t count;
std::string name;
rdwrT rdwr;
};
template <typename T>
class encodedTag
{
public:
encodedTag(vector<tagTypeInfo> tagInfo_) : tagInfo(tagInfo_)
{
int start = 0;
for(auto & tag : tagInfo)
{
tag.start = start;
tag.last = start + tag.count - 1;
start = start + tag.count;
}
}
uint16_t encode(uint16_t tag, T tagType)
{
assert(tag<tagInfo[tagType].count)
return( tagInfo[tagType].start + tag );
}
std::tuple<uint16_t, T> decode(uint16_t encodedTag)
{
int type = 0;
uint16_t tag;
// simple linear search as there are only a few entries
for (auto it = begin(tagInfo); it != end(tagInfo); it++)
{
if (encodedTag >= it->start && encodedTag < it->last )
{
// tag is in the range
return {encodedTag - it->start , (T)type};
}
type++;
}
assert(false);
return {0,(T)0};
}
std::string getName(T tagType) {return(tagInfo[tagType].name);}
rdwrT getRdwr(T tagType) {return(tagInfo[tagType].rdwr);}
private:
std::vector<tagTypeInfo> tagInfo;
};
extern std::vector<tagTypeInfo> rdTag;
extern std::vector<tagTypeInfo> wrTag;
//using rdTagEncode = encodedTag<rdTagT>(rdTag) <-- error
The cpp file contains:
std::vector<tagTypeInfo> rdTag {
{0, 0, NUM_HOSTRDTAG, "HostRdTag", RDWR_RD},
{0, 0, NUM_SYSRDTAG, "SysRdTag", RDWR_RD},
{0, 0, NUM_GCRDTAG, "GCRdTag", RDWR_RD}
};
std::vector<tagTypeInfo> wrTag {
{0, 0, NUM_HOSTWRTAG, "HostWrTag", RDWR_WR},
{0, 0, NUM_SYSWRTAG, "SysWrTag", RDWR_WR},
{0, 0, NUM_GCWRTAG, "GCWrTag", RDWR_WR}
};
My goal is to be able to just declare an encoder in the code elsewhere with
rdTagEncode myEncode;
However I cant seem to figure out the right syntax to do this. Any suggestions?
Using a derived class was the best solution. Thanks for the suggestion #appleapple
class encodedRdTag : public encodedTag<rdTagTypeT>
{
public:
encodedRdTag() : encodedTag({
{0, 0, NUM_HOSTRDTAG, "HostRdTag", RDWR_RD},
{0, 0, NUM_SYSRDTAG, "SysRdTag", RDWR_RD},
{0, 0, NUM_GCRDTAG, "GCRdTag", RDWR_RD}
}) {};
};
class encodedWrTag : public encodedTag<wrTagTypeT>
{
public:
encodedWrTag() : encodedTag({
{0, 0, NUM_HOSTRDTAG, "HostRdTag", RDWR_RD},
{0, 0, NUM_SYSRDTAG, "SysRdTag", RDWR_RD},
{0, 0, NUM_GCRDTAG, "GCRdTag", RDWR_RD}
}) {};
};
For completeness, here is the "dispatch based on type" method which I mentioned in comment above.
NOTE: this code doesn't work in original question as the rdTag and wrTag are same type thus independent of the class template T, but according to your own answer this may be actually what happends.
#include <vector>
struct tagTypeInfo{};
struct rdTagTypeT{};
struct wrTagTypeT{};
std::vector<tagTypeInfo> get_default_info(rdTagTypeT); // return wrTag
std::vector<tagTypeInfo> get_default_info(wrTagTypeT); // return wdTag
template <typename T>
struct encodedTag
{
encodedTag():encodedTag(get_default_info(T{})){}
encodedTag(std::vector<tagTypeInfo> tagInfo) : tagInfo(tagInfo){};
std::vector<tagTypeInfo> tagInfo;
};
using encodedRdTag = encodedTag<rdTagTypeT>;
using encodedWrTag = encodedTag<wrTagTypeT>;
void foo(){
encodedRdTag rd;
encodedWrTag rw;
}
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}
}
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;
}
I have a struct called CoolStruct:
struct CoolStruct
{
int id;
uint32 type;
uint32 subtype;
String name;
};
I have a vector of these structs as well:
std::vector<CoolStruct> coolVector;
I want to create a bunch of structs which have predefined values to push_back into this coolVector. I'd like to keep the code from getting cludgy and ugly. I would really like to keep this notation:
CoolStruct t = {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")};
coolVector.push_back(t);
CoolStruct t = {2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")};
coolVector.push_back(t);
But of course this doesn't work... Not allowed to do a reinitialization. Is there any other solution to make this as readable as possible? The only alternative I can think of is it manually set each paramater of the struct:
t.id = whatever; t.type = somethingelse; t.subtype = thisisalotofcode; t.name = justtosetupthisvector;
coolVector.push_back(t);
how about:
CoolStruct t1 = {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")};
coolVector.push_back(t1);
CoolStruct t2 = {2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")};
coolVector.push_back(t2);
In C++0x, I think you should be able to do:
CoolStruct t;
t = {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")};
coolVector.push_back(t);
t = {2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")};
coolVector.push_back(t);
or even:
coolVector.push_back({1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")});
coolVector.push_back({2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")});
In fact, if you really want to get creative (and you don't have any previous elements that you want to keep), you can replace the whole vector with this syntax:
coolVector = {
{1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")},
{2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")}
};
if you add a simple constructor:
struct CoolStruct
{
CoolStruct(int id, uint32 type, uint32 subtype, String name) : id(id), type(type), subtype(subtype), name(name) {}
int id;
uint32 type;
uint32 subtype;
String name;
};
you can then do this:
CoolVector.push_back(CoolStruct(1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")));
CoolVector.push_back(CoolStruct(2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")));
Not sure how to explain it - I'm pretty new to C++, but... let me try:
Let's say I have 300+ names (Jeff, Jack...) with 300+ int values (0 or 1). In JS I would use JSON. Something like this:
var people = {"person": [
{"name": "Jeff","val": 0},
{"name": "Jill","val": 1},
{"name": "Jack","val": 0},
{"name": "Jim","val": 1},
{"name": "John","val": 0}
]}
What's the best way to do this in C++?
Thanks.
If you can have duplicate names you can't use a map, so you could use something like this:
struct Person
{
Person( const std::string & n, int v ) : name(n), val(v) {}
std::string name;
int val;
};
int main()
{
std::vector<Person> people;
people.push_back( Person( "Jeff", 0 ) );
people.push_back( Person( "Jill", 1 ) );
...
}
If you wanted uniqueness of names you could do something like this:
std::map<std::string, int> people;
people["Jeff"] = 0;
people["Jill"] = 1;
or
std::map<std::string, Person> people;
people["Jeff"] = Person("Jeff",0);
people["Jill"] = Person("Jill",1);
If you're using this code a lot you can clean up the repeated cruft.
template<typename K, typename V>
struct BuildMap
{
BuildMap() : map_() {}
BuildMap<K,V>& operator()( const K & key, const V & value )
{
map_[key]=value;
return *this;
}
std::map<K,V> operator()() { return map_; }
std::map<K,V> map_;
};
std::map<std::string,int> people = BuildMap<std::string,int>()
( "Jeff", 0 )
( "Jill", 1 )
( "John", 1 )
();
Hope this gives you some ideas.
Take a look at jsoncpp - it is a lightweight json parser, that makes it very easy to use json in your c++ project.
http://sourceforge.net/projects/jsoncpp/
Then you can create a text file, write some entries in the json format there and then open this file in your c++ program. There are plenty of tutorials of how to do it with jsoncpp.
Try looking at std::map.
link here
http://www.cplusplus.com/reference/stl/map/
It's an associative container that is similar to a dictionary. Something like this?
#include <map>
#include <string>
std::map<string,int> person;
void initPeople(){
person["Jeff"] = 0;
person["Jill"] = 1;
person["Jack"] = 0;
person["Jim"] = 1;
person["John"] = 0;
}