I am having a problem trying to load a map that has another map/vector combination as the value with structs. Below is my code which I have tried to simplify as much as I could:
//These are the structs
struct Order
{
std::string A;
std::string B;
};
struct Card
{
std::string C;
std::string D;
};
struct Item
{
std::string E;
std::string F;
};
//this is the method that will read and load the map
void LoadMap(ListofValues object)
{
std::map<Order, std::map<Item, std::vector<Card>>> records; //THIS is the data structure I'm trying to store into
//ListofValues is a list passed that holds all these values that will need to be put into my map
for(std::vector<ListofValues>::iterator vIter= object.begin(); vIter != object.end(); ++vIter)
{
std::string sReceiptRecord = (*vIter).getReceipt(m_StdOrderConfirmVer);
Order order = {(*vIter).getA,(*vIter).getB};
Item item = {(*vIter).getC,(*vIter).getD};
Card card = {wws::String((*vIter).getE), (*vIter).getF};
records[order][item].push_back(card); //load into my map
}
}
So I will have an object passed that contains a list of all the values (ListofValues). I will iterate through that list and with the getter methods, I will store those values into the structs (getE returns a Long which is why the conversion was necessary). Is there a step I'm missing
An error I'm getting is:
error C2678: binary '<' : no operator found which takes a left-hand operand of type 'const Order' (or there is no acceptable conversion)
You need to provide an operator < for your struct to be used as a key for the map, see this question: Struct as a key in a std::map
ListOfValues is the TYPE of the parameter passed to LoadMap, object is the actual variable.
In your for loop, you need to say object.begin() and object.end().
I'm getting very different compiler errors than what you say you're getting. Did you post the right code?
Here's what I see: https://godbolt.org/g/xl4zWw
Related
Guys I have a function like this (this is given and should not be modified).
void readData(int &ID, void*&data, bool &mybool) {
if(mybool)
{
std::string a = "bla";
std::string* ptrToString = &a;
data = ptrToString;
}
else
{
int b = 9;
int* ptrToint = &b;
data = ptrToint;
}
}
So I want to use this function in a loop and save the returned function parameters in a vector (for each iteration).
To do so, I wrote the following struct:
template<typename T>
struct dataStruct {
int id;
T** data; //I first has void** data, but would not be better to
// have the type? instead of converting myData back
// to void* ?
bool mybool;
};
my main.cpp then look like this:
int main()
{
void* myData = nullptr;
std::vector<dataStruct> vec; // this line also doesn't compile. it need the typename
bool bb = false;
for(int id = 1 ; id < 5; id++) {
if (id%2) { bb = true; }
readData(id, myData, bb); //after this line myData point to a string
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
}
}
Or is there a better way to do that without template? I used c++11 (I can't use c++14)
The function that you say cannot be modified, i.e. readData() is the one that should alert you!
It causes Undefined Behavior, since the pointers are set to local variables, which means that when the function terminates, then these pointers will be dangling pointers.
Let us leave aside the shenanigans of the readData function for now under the assumption that it was just for the sake of the example (and does not produce UB in your real use case).
You cannot directly store values with different (static) types in a std::vector. Notably, dataStruct<int> and dataStruct<std::string> are completely unrelated types, you cannot store them in the same vector as-is.
Your problem boils down to "I have data that is given to me in a type-unsafe manner and want to eventually get type-safe access to it". The solution to this is to create a data structure that your type-unsafe data is parsed into. For example, it seems that you inteded for your example data to have structure in the sense that there are pairs of int and std::string (note that your id%2 is not doing that because the else is missing and the bool is never set to false again, but I guess you wanted it to alternate).
So let's turn that bunch of void* into structured data:
std::pair<int, std::string> readPair(int pairIndex)
{
void* ptr;
std::pair<int, std::string> ret;
// Copying data here.
readData(2 * pairIndex + 1, ptr, false);
ret.first = *reinterpret_cast<int*>(ptr);
readData(2 * pairIndex + 2, ptr, true);
ret.second = *reinterpret_cast<std::string*>(ptr);
}
void main()
{
std::vector<std::pair<int, std::string>> parsedData;
parsedData.push_back(readPair(0));
parsedData.push_back(readPair(1));
}
Demo
(I removed the references from the readData() signature for brevity - you get the same effect by storing the temporary expressions in variables.)
Generally speaking: Whatever relation between id and the expected data type is should just be turned into the data structure - otherwise you can only reason about the type of your data entries when you know both the current ID and this relation, which is exactly something you should encapsulate in a data structure.
Your readData isn't a useful function. Any attempt at using what it produces gives undefined behavior.
Yes, it's possible to do roughly what you're asking for without a template. To do it meaningfully, you have a couple of choices. The "old school" way would be to store the data in a tagged union:
struct tagged_data {
enum { T_INT, T_STR } tag;
union {
int x;
char *y;
} data;
};
This lets you store either a string or an int, and you set the tag to tell you which one a particular tagged_data item contains. Then (crucially) when you store a string into it, you dynamically allocate the data it points at, so it will remain valid until you explicitly free the data.
Unfortunately, (at least if memory serves) C++11 doesn't support storing non-POD types in a union, so if you went this route, you'd have to use a char * as above, not an actual std::string.
One way to remove (most of) those limitations is to use an inheritance-based model:
class Data {
public:
virtual ~Data() { }
};
class StringData : public Data {
std::string content;
public:
StringData(std::string const &init) : content(init) {}
};
class IntData : public Data {
int content;
public:
IntData(std::string const &init) : content(init) {}
};
This is somewhat incomplete, but I think probably enough to give the general idea--you'd have an array (or vector) of pointers to the base class. To insert data, you'd create a StringData or IntData object (allocating it dynamically) and then store its address into the collection of Data *. When you need to get one back, you use dynamic_cast (among other things) to figure out which one it started as, and get back to that type safely. All somewhat ugly, but it does work.
Even with C++11, you can use a template-based solution. For example, Boost::variant, can do this job quite nicely. This will provide an overloaded constructor and value semantics, so you could do something like:
boost::variant<int, std::string> some_object("input string");
In other words, it's pretty what you'd get if you spent the time and effort necessary to finish the inheritance-based code outlined above--except that it's dramatically cleaner, since it gets rid of the requirement to store a pointer to the base class, use dynamic_cast to retrieve an object of the correct type, and so on. In short, it's the right solution to the problem (until/unless you can upgrade to a newer compiler, and use std::variant instead).
Apart from the problem in given code described in comments/replies.
I am trying to answer your question
vec.push_back(id, &myData<?>); //how can I set the template param to be the type myData point to?
Before that you need to modify vec definition as following
vector<dataStruct<void>> vec;
Now you can simple push element in vector
vec.push_back({id, &mydata, bb});
i have tried to modify your code so that it can work
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
struct dataStruct
{
int id;
T** data;
bool mybool;
};
void readData(int &ID, void*& data, bool& mybool)
{
if (mybool)
{
data = new string("bla");
}
else
{
int b = 0;
data = &b;
}
}
int main ()
{
void* mydata = nullptr;
vector<dataStruct<void>> vec;
bool bb = false;
for (int id = 0; id < 5; id++)
{
if (id%2) bb = true;
readData(id, mydata, bb);
vec.push_back({id, &mydata, bb});
}
}
Can anyone guide me on how to solve this problem.
I have a boost::variant.
typedef boost::variant <
int,
std::string,
bool,
double,
vector<int>,
vector<string>,
vector<bool>,
vector<double>
> boostVar;
I am trying to create overload [] operator as member function of a class ABC something like this (this is just a dummy implementation)
class ABC
{
//some map of (key, value) pair that where key is string and value is of type boostVar
boostVar [](const string key)
{
boostVar temp;
//some operation that fills up temp based on value of key
return temp;
}
}
So while retrieving the a particular value using this implementation, it forces user to specify
int key1Val = boost::get<int>(ABC["KEY1"]);
bool key2Val = boost::get<bool>(ABC["KEY2"]);
vector<int> key3Val = boost::get<vector<int>>(ABC["KEY3"]);
my question is:
How should I go about implementing this if I want to access the values like below (i.e. without boost::get<>)
int key1Val = ABC["KEY1"];
bool key2Val = ABC["KEY2"];
vector<int> key3Val = ABC["KEY3"];
The implementation should give warning to user if the say: KEY1 does not match int, KEY2 does not match bool and so on.
You'd need to use a class to wrap the boost variant and add the conversion behaviours. At it's simplest - in the common case where realistically client code won't be trying to delete dynamically allocated instances using pointers to the base (boost::variant<...>*) - it could look something like this:
struct Variant : boost::variant<int, std::string, ...etc...>
{
operator int() const { return boost::get<int>(*this); }
operator std::string() const { return boost::get<std::string>(*this); }
...etc...
};
This will provide the same checks get<> provides: compile time checks that you're trying to assign to one of the types the variant could hold at runtime, and runtime checks that it does actually hold the exact destination type when you try to assign from it.
If you can't be sure client code won't delete via the base class pointer, consider private inheritance or composition (you will need to do more work to expose any other variant functionality your client code may want to access).
(ABC::operator[](const std::string& key) const can just return such a Variant).
I have the following typedefs
struct PolicyRuleInfo{
BearerQoSInfo stBearerQoS;
TFTInfo stTFTInfo;
PolicyRuleInfo(){};
PolicyRuleInfo( BearerQoSInfo const& qos, TFTInfo const& tft)
: stBearerQoS(qos), stTFTInfo(tft)
{ }
};
typedef map<string, PolicyRuleInfo> listOfPolicyRuleInfo;
struct IPAddressPolicyRulesInfo{
CIPAddress ipAddress;
listOfPolicyRuleInfo policyRules;
IPAddressPolicyRulesInfo(){};
IPAddressPolicyRulesInfo(CIPAddress ipaddr, string policyRuleName, PolicyRuleInfo policyRule): ipAddress(ipaddr){policyRules[policyRuleName]=policyRule;};
void addPolicycyRule(string policyRuleName, PolicyRuleInfo policyRule) { policyRules[policyRuleName]=policyRule; }
};
typedef map<string, IPAddressPolicyRulesInfo> APN2PolicyRules;
typedef map<string, APN2PolicyRules> IMSI2APNPolicyRules;
Later in a cpp:
u32 CPCRF::m_pNumPCCRulesViaCLI = 0;
listOfPolicyRuleInfo CPCRF::m_mlistOfCliConfiguredPolicyRules;
// map IMSI to PolicyRules
IMSI2APNPolicyRules CPCRF::m_mIMSI2PCRFInfo;
// Assign some default Policies (Applicable to all subscribers) , can be changed via CLI
listOfPolicyRuleInfo m_mlistOfCliConfiguredPolicyRules = boost::assign::map_list_of("PolicyRule_Internet", PolicyRuleInfo( BearerQoSInfo(9), TFTInfo()))
("PolicyRule_Voice_C", PolicyRuleInfo( BearerQoSInfo(5), TFTInfo()))
("PolicyRule_Voice_U", PolicyRuleInfo( BearerQoSInfo(1), TFTInfo()));
listOfPolicyRuleInfo::iterator it = m_mlistOfCliConfiguredPolicyRules.find("PolicyRule_Internet");
if (it != m_mlistOfCliConfiguredPolicyRules.end() )
{
IMSI2APNPolicyRules::iterator itr= m_mIMSI2PCRFInfo.find(imsi);
if (itr == m_mIMSI2PCRFInfo.end() )
{
IPAddressPolicyRulesInfo ipAddrPolicyRules(ueIPAddress, "PolicyRule_Internet", it->second);
APN2PolicyRules apn2policy["Apn_Internet"]=ipAddrPolicyRules;
m_mIMSI2PCRFInfo[imsi] = apn2policy;
I get the error saying that size of array 'apn2policy' has non-integral type 'const char [13]'
Earlier the I had declared listOfPolicyRuleInfo as typedef list, but when changed to map, I get this error.
thanks,
pdk
APN2PolicyRules apn2policy["Apn_Internet"]=ipAddrPolicyRules;
This line is trying to declare an array of APN2PolicyRules but the size argument is a string literal which doesn't make any sense.
What you most likely meant to do is:
APN2PolicyRules apn2policy; // create map
apn2policy["Apn_Internet"]=ipAddrPolicyRules; // set rule
APN2PolicyRules apn2policy["Apn_Internet"]=ipAddrPolicyRules;
This is wrong; you are declaring an array of "Apn_Internet" × APN2PolicyRules objects, which is clearly nonsense!
You must first create the map then use it:
APN2PolicyRules apn2policy; // (if it doesn't already exist)
apn2policy["Apn_Internet"] = ipAddrPolicyRules;
As you can see, the Foo[Bar] syntax means different things in different contexts.
My program is to evaluate and characterize time series information. There are about 90 distinct signals that the data may have. Each signal has a unique formula and distinct set of parameters and values. This code and my problem(s) with it is for loading these values from a config file. Compiler is VS 2010.
Each signal is represented by a class, here illustrated with the class TRI{}, and each such class derives from the class SIGNAL{}. SIGNAL contains a static map (my actual code uses unordered_map) which is to hold the pairs of signal names and pointers to the signal's member function which assigns the parameter values to their respective variables. My problem is with manipulating this member function.
Apparently, the address of the signal's member function, in this code &TRI::load_cfg_vals, is never stored in the map, sig_map. So it seems from the debugger. When I try to call the TRI signal's load function, the compiler says I'm trying to call something that's not a function. Please see the code for some of my failed attempts.
How can I get this to work with these objects? I really don't know what the problem is, and worse, I don't know what I'm not understanding about how to use STL or C++.
(I'm about ready to give up. I'm considering an alternative, more C-like approach. Using a map, associate each signal name with a unique integer (already in the actual code - they're all represented as unique single bits). Load each element of an array of void pointers with the address of the load function of the signal whose integer value is the offset into the array of that element. The first way I chose, the code below, seemed easier to maintain, a little more high-level.)
Among the many questions and answers I studied before posting this were
member function pointers and inheritance
C++ Map of string and member function pointer
C++ pointers to member functions
C++ Call pointer to member with a map from a const function
TIA
#include <iostream>
#include <map>
#include <string>
using namespace std;
typedef std::map< string, void *> ARG_MAP;
typedef ARG_MAP::iterator ARG_ITR;
typedef std::pair < ARG_ITR, bool> ARG_PAIR;
// forward decl
class SIGNAL;
typedef int (SIGNAL::*PF)(void);
typedef std::map< string, PF> SIG_MAP;
typedef SIG_MAP::iterator SIG_MAP_ITR;
typedef std::pair < SIG_MAP_ITR, bool> SIG_MAP_PAIR;
class SIGNAL
{
public:
ARG_MAP arg_map;
ARG_ITR ai;
ARG_PAIR ap;
static SIG_MAP sig_map;
SIGNAL() {};
~SIGNAL(){};
virtual int calc() = 0;
virtual int load_cfg_vals() = 0;
};
// tried globals versus members, no difference
SIG_MAP SIGNAL::sig_map;
SIG_MAP_ITR smi;
SIG_MAP_PAIR smp;
class TRI: public SIGNAL
{
public:
float f;
int calc(){return 1;}
int load_cfg_vals()
{
// the f arg
ai = arg_map.find("f_descriptive_name");
*(float *) ai->second = (float)12.005;
return 1;
};
TRI()
{
// associates the TRI class function 'load_cfg_vals()' with the
// signal name 'tri'
SIGNAL::sig_map.insert(std::make_pair ("tri",
(PF) &TRI::load_cfg_vals));
// this apparently doesn't load the address of the function, see below
//sig_map.insert(std::make_pair ("tri",&TRI::load_cfg_vals));
// fails with error C2440: 'initializing' : cannot convert from
// from 'int (__thiscall TRI::* )(void)' to 'PF '
//SIGNAL::sig_map.insert( map<string, PF>::value_type("tri",
// dynamic_cast< & SIGNAL::load_cfg_vals> (&TRI::load_cfg_vals) ));
// C2059: syntax error : '&'
// so, maybe this is right but for my lack of understanding of what
// types are involved/required here
// contains the list of descriptive names of the signal's parameters
// and the addresses of the variables that hold the parameters'values
arg_map.insert(std::make_pair ("f_descriptive_name", (void*) &f));
};
~TRI(){};
};
int main(void)
{
TRI tri;
PF pf;
char * input_str = "tri"; // this and the names of the many other
// signals would be read from the cfg file
// while there are still more signal names to read in
// while( fscanf(...input_str...) { removed
if( (smi = tri.sig_map.find (input_str)) == tri.sig_map.end())
cout << "'" << input_str << "' not found\n";
else
{
// smi->second is supposed to contain the function of the
// signal class that is to properly interpret and handle
// the list of values stored in the cfg file
//(smi->second)();
// error C2064: term does not evaluate to a function taking
// 0 arguments
string s = smi->first; // OK
pf = (PF)smi->second;
// Doesn't contain the address of the function that was
// loaded, above, in TRI(). The debugger identifies
// it as TRI::`vcall'{4}', I don't know what that is.
// Debugger emits the entire type of the operator and
// its return value, but I can't get it to format for
// proper display here. If someone wants to see it,
// I'll supply it unformatted.
//int z = (*pf)();
// error C2064: term does not evaluate to a function taking 0
// arguments
// the following don't help the value in pf. same error C2064 or
// complaints about improper use of the casts
//pf = reinterpret_cast <int (__thiscall *)(void)>(smi->second);
//pf = static_cast <int (__thiscall *)(void)>(smi->second);
}
// } // end while removed
return 1;
}
Keep it simple, instead of trying to insert that pointer-to-member type into a map just try to do the conversion to the PF type:
PF pf = &TRI::load_cfg_vals;
This doesn't compile, for the reasons explained in an answer to one of the questions you linked to, just like this reduced example doesn't:
struct A {
virtual int f() = 0;
};
struct B : A {
int f() { return 0; }
};
int (A::*pf)() = &B::f;
So if that doesn't compile, your version that relies on that but in a more complicated situation, is not going to compile either.
Why can't you just do this instead:
SIGNAL::sig_map.insert(std::make_pair ("tri",
&SIGNAL::load_cfg_vals));
The type of &SIGNAL::load_cfg_vals is the same type as you're trying to store in the map, so it works.
This doesn't compile because the template argument for dynamic_cast must be a type not a pointer-to-member:
SIGNAL::sig_map.insert( map<string, PF>::value_type("tri",
dynamic_cast< & SIGNAL::load_cfg_vals> (&TRI::load_cfg_vals) ));
And dynamic_cast is for converting pointers to polymorphic types, not pointer-to-member types, this would compile instead, but it's better to avoid the cast:
SIGNAL::sig_map.insert( map<string, PF>::value_type("tri",
static_cast<PF> (&TRI::load_cfg_vals) ));
Also, why are all your types and typedefs in ALL_CAPS? Stop shouting, ALL_CAPS is for macros, don't name your types like that.
How it is possible to provide all three functions: msgpack_pack, msgpack_unpack and msgpack_object (also, what are meanings of them, exactly?) for a user-defined C++ class (in the same way MSGPACK_DEFINE does it for non-array POD/UD types) containing Plain Old Data arrays (such as dobule[] or char[]), so my class will play nicely with higher-level classes, containg this class in map or a vector?
Is there any examples of implementing them for your own class or at least msgpack C++ api documentation?
The only link to possible api reference i've found was http://redmine.msgpack.org/projects/msgpack/wiki ; but it is dead now.
Say, i have a struct like
struct entity {
const char name[256];
double mat[16];
};
What would be a msgpack_* member functions for it?
Thanks to guy who -1'd my question, i felt grievance and explored the actual undocumented codebase of msgpack. Here is the example of mentioned earlier functions with sort of explanation, in amount of my (vastly incomplete due to missing docs) understanding:
struct entity {
char name[256];
double mat[16];
// this function is appears to be a mere serializer
template <typename Packer>
void msgpack_pack(Packer& pk) const {
// make array of two elements, by the number of class fields
pk.pack_array(2);
// pack the first field, strightforward
pk.pack_raw(sizeof(name));
pk.pack_raw_body(name, sizeof(name));
// since it is array of doubles, we can't use direct conversion or copying
// memory because it would be a machine-dependent representation of floats
// instead, we converting this POD array to some msgpack array, like this:
pk.pack_array(16);
for (int i = 0; i < 16; i++) {
pk.pack_double(mat[i]);
}
}
// this function is looks like de-serializer, taking an msgpack object
// and extracting data from it to the current class fields
void msgpack_unpack(msgpack::object o) {
// check if received structure is an array
if(o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
const size_t size = o.via.array.size;
// sanity check
if(size <= 0) return;
// extract value of first array entry to a class field
memcpy(name, o.via.array.ptr[0].via.raw.ptr, o.via.array.ptr[0].via.raw.size);
// sanity check
if(size <= 1) return;
// extract value of second array entry which is array itself:
for (int i = 0; i < 16 ; i++) {
mat[i] = o.via.array.ptr[1].via.array.ptr[i].via.dec;
}
}
// destination of this function is unknown - i've never ran into scenary
// what it was called. some explaination/documentation needed.
template <typename MSGPACK_OBJECT>
void msgpack_object(MSGPACK_OBJECT* o, msgpack::zone* z) const {
}
};