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;
}
Related
For context I am recreating a Pokemon game in c++(I am new to C++ i have only 1 year xp in programming and i was programming in C). But i have issue with the organisation of my code.
Here is my problem: I don't know what to put in class and what to put in struct.
For example in my current code my Pokemon and my Attaque are 2 different class. I have done that because of the fact that I want the 2 of them to be init with info in a file. But if the Pokemon are fighting they need to have access to the Attaque. But when generating my Pokemon some stat change when it's affected by item. Like shiny % is affected by Shiny Charm. So i need to have access to my bag too.
The problem here is that I am making a lot of class friend (right now Attaque is friend of Pokemon and Pokemon is friend of bag). And I have read that it's maybe an organisation code issue.
I have thought about making getters for example for the Shiny Charm, but I don't know if it's good or not.
Here is my Pokemon class. nature_e, status_e and type_e are enum class.
class Pokemon {
private:
bool m_is_shiny { false };
bool m_is_pokerus { false };
short m_level { 0 };
int m_id { 0 };
int m_exp { 0 };
std::array<int, 2> m_texture_coord { 0, 0 };
std::array<unsigned char, 6> m_iv {0, 0, 0, 0, 0, 0};
std::array<unsigned char, 6> m_ev {0, 0, 0, 0, 0, 0};
std::array<unsigned char, 6> m_base_stat {0, 0, 0, 0, 0, 0};
std::array<unsigned char, 8> m_stat {0, 0, 0, 0, 0, 0, 0, 0};
nature_e m_nature {nature_e::NONE};
status_e m_status {status_e::NONE};
std::array<type_e, 2> m_type {type_e::NONE, type_e:: NONE};
Texture2D m_texture;
std::string m_name { "Non" };
std::string m_item { "non" };
std::string m_sprite_path { "None" };
std::array<Attaque, 4> m_atk { Attaque(), Attaque(), Attaque(), Attaque() };
public:
Pokemon()
{
}
Pokemon(int id, short level);
};
Here is my Attaque class:
class Attaque {
private:
bool m_phy_or_spe;
int m_damage;
type_e m_type;
double m_effect_precision;
double m_precision;
std::string m_name;
public:
Attaque()
{
}
Attaque(int id);
};
I am creating a model that is empty like so:
struct TestNet : torch::nn::Module {
TestNet() {
}
torch::Tensor Forward(torch::Tensor x)
{
return x;
}
};
I then register new modules to the model:
auto net = std::make_shared<TestNet>();
torch::nn::ModuleHolder<ConvLayer> conv(1, 1, 3, 1, 1);
net->register_module("conv1", conv);
Where ConvLayer is a Module with a convolutional layer:
struct ConvLayer : torch::nn::Module {
ConvLayer() {}
ConvLayer(int in_ch, int out_ch, int kernel, int pad, int stride)
: conv1(torch::nn::Conv2dOptions(in_ch, out_ch, kernel)
.stride(stride)
.padding(pad)
.bias(false))
{
register_module("Conv1", conv1);
}
torch::Tensor Forward(torch::Tensor x)
{
return conv1(x);
}
torch::nn::Conv2d conv1{ nullptr };
};
I can print out the parameters of TestNet now and see the convolutional layer, however I can not utilize it in a forward pass. What am I missing to do this?
I found a way to do this using torch::nn::Sequential, hope this helps anyone else:
struct TestNet2 : torch::nn::Module {
TestNet2() {
layers = register_module("layers", torch::nn::Sequential());
}
template <typename T>
void sequentialLayer(T Layer)
{
layers->push_back(Layer);
}
torch::Tensor Forward(torch::Tensor x)
{
return layers->forward(x);
}
torch::nn::Sequential layers;
};
...
auto net = std::unique_ptr<TestNet2>();
auto convLayer = torch::nn::Conv2d(torch::nn::Conv2dOptions(1, 1, 3)
.stride(1)
.padding(1)
.bias(false));
net->sequentialLayer(convLayer);
Why is there no direct assigment during declaration of a struct possible in C++?
I have the following C code that wont work with C++ compiler:
static const struct {
struct structtype1 header;
struct {
struct structtype2 intf;
struct structtype3 src;
} foo1, foo2;
} bar = {
.header = {
.byte1 = 0x23,
.length = 12,
.count1 = 4,
.count2 = 4,
},
.foo1= {
.intf = {
.data = 0x23,
.len = 2,
.ep = 3,
},
.src= {
.data = 0x21,
.len = 4,
.ep = 2,
},
},
.foo2= {
.intf = {
.data = 0x17,
.len = 11,
.ep = 2,
},
.src= {
.data = 0x20,
.len = 2,
.ep = 1,
},
},
};
you have two choices:
1.use constructors for that
this will define values for members but all structs will be the same
struct _pnt { int x,y,z; _pnt() { x=0; y=0; z=0; } };
_pnt p0,p1,p2; // all points are initialized to (0,0,0)
2.use definition as usual it still works in any C++ compiler I used
I think this is what you want
Do not forget that the order of members is the same as in declaration !!!
struct _pnt { int x,y,z; };
_pnt p0={0.0,0.0,0.0},
p1={1.0,0.0,0.0},
p2={0.0,1.0,0.0};
problem is you have to init all members not just some !!!
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")));
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.