I have two structs like this
struct Activity {
int id;
string Description;
int parameter1;
int parameter2;
int parameter3;
int parameter4;
etc...
}
Activity A1;
A1.id=0;
A1.parameter1=50;
Activity A2;
A2.id=0;
A2.parameter1=55;
I would like to compare them, to show what members are different ?
In this case something like :
paameter1 is different...
Thanks
The best solution to do this may be to write public method inside the structure which will compare themselves with structure passed through parameter.
This will look like this
struct Activity {
int id;
string Description;
int parameter1;
int parameter2;
int parameter3;
int parameter4;
etc...
public:
bool compare(const Activity& param)
{
//...compare structs here like:
if (id != param.id)
//write something
//etc...
//at the end you can also return bool that indicates that structs are equal or not
return true;
}
}
This will obviously work only with two the same classes unless you write more comparison methods, but it may be difficult to compare two different structures.
There is also other way to compare two variables (including structs). For this a memcmp() function can be used, but it will not tell you directly, which fields are different.
Edited according to what #Tony_D said.
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});
}
}
I need to store objects of exactly two types in a vector, the both types have almost nothing in common.
After storing them in the vector, I want to iterate over that vector and perform an action, depending on the type.
my thoughts so far:
Polymorphism. Overkill, and wouldn't help me much, as I probably would do this:
if(dynamic_cast<T1>() != nullptr) {
...
} else {
...
}
Merge both types (methods and fields) and add a boolean, representing if its type 1 or 2.
Both patterns seem totally clumsy to me, there is propably a total simple solution, I simply don't see.
The first type is something like this :
struct PatternMatch {
int length;
int indexInDict;
}
The second
one:
struct NoMatch {
std::string rawChars;
}
Use boost::variant or any other "stack-based discriminated union container". I also suggest visiting the variant using lambdas.
// Either `A` or `B`.
using my_type = boost::variant<A, B>;
std::vector<my_type> my_vec;
// ...`emplace_back` stuff into `my_vec`...
auto visitor = make_lambda_visitor<void>(
[](A&) { /* do something with A */ },
[](B&) { /* do something with B */ }
);
for(auto& x : my_vec)
{
boost::apply_visitor(visitor, x);
}
Note that C++17 will have std::variant.
If you know that you have only two types and this number won't grow in future, a C-ish tagged union is enough and easy to use:
struct PatternMatch {
int length;
int indexInDict;
};
struct NoMatch {
std::string rawChars;
};
struct TaggedUnion {
enum { MATCH, NO_MATCH } flag;
union {
PatternMatch match;
NoMatch noMatch;
};
};
Now, you can create a vector of TaggedUnions and check the flag data member to find out the actual type of each element.
I have a take home test that it work a large percentage of my grade. These 3 questions are on it and they are worth half the test. I was wondering if someone could kindly review my quiz and make sure they are correct for me. I’m a worrier and I want to make sure they are correct. Thank you in advance!
Implement the constructor for the class called "SimpleMath". The constructor takes two integer parameters; "var1" and "var2". The constructor is to store the value that was passed into "var1" into the private integer member variable "m_value1" and the value that was passed into "var2" into the private integer member variable "m_value2"
class SimpleMath
{
public:
SimpleMath(int var1, int var2) : m_value1(var1), m_value2(var2) {};
int getVar1() const
{
return m_value1;
}
int getVar2() const
{
return m_value2;
}
private:
int m_value1;
int m_value2;
};
Implement the "Multiply" method for the "SimpleMath" class. This method does not require any parameters and returns an integer value. This method should multiply the values stored in the classes private integer member variables "m_value1" and "m_value2" the resulting value is returned. Assume that "m_value1" and "m_value2" were loaded inside the classes constructor.
class SimpleMath
{
public:
SimpleMath(int var1, int var2);
int Mutiply= m_value1* m_value2;
private:
int m_value1;
int m_value2;
};
Write a class definition called "SimpleMath" that has a constructor that takes two integers "var1" and "var2". It has four public methods that take no parameters and return an integer value; "Add","Subract","Divide" and "Multiply". The class has two private member variables of type integer; "m_value1" and "m_value2".
class SimpleMath
{
SimpleMath(int var1, int var2);
public:
int Add;
int Subract;
int Divide;
int Multiply;
private:
int m_value1;
int m_value2;
};
Am I to assume you have no prior programming experience?
At any rate, the first part looks ok. What the : denotes is the initializer list. It can, and is, correctly used to initialize a class's members.
Second part, you got it dead wrong I am afraid.
First of, you've not implemented the method Multiply() there, you've just declared a variable.
Instead do this:
int Multiply()
{
int sum = m_value1 * m_value2;
return sum;
}
For brevity's sake, you can also do this:
int Multiply()
{
return m_value1 * m_value2;
}
Does the same thing.
Also note that the answer from question 1 has not carried over to question 2, ie the constructor is incomplete. It won't compile.
As for question 3, it's just question 2 all over again, except you've also got to implemented the three remaining arithmetic functions. Suffice it to say, I am sure you can figure it out.
I am working on an c++ hw assignment so I will try not to post too much code as possible, what we are working on is as following: we have a class that include a public swap function (along with insert and delete functions and such) and a private struct array to store the data.
something like:
Class set
public:
set(int dimension);
insert();
delete();
swap(set& swapset);
private:
struct *set;
now in the main we have set s1 and set s2, when I run swap like so: s1.swap(s2); s1 and s2 will swap the whole array and we need to keep the dimension of each array (so if s1 was set=new set[3] and s2 is set=new set[5]) after swap s1 is [5] and s2 is [3]
I was able to use insert and delete functions to swap the arrays when it was fixed dimension but I can't figure out how to change the dimension of the arrays during the swap function since the *set is private right?
thanks in advance for all the help!
edit: I added some parts of the code since I can't explain it correctly:
set::set()
:counter(0),m_size(0),flag(0)
{
m_set=new set[DEFAULT_MAX_ITEMS];
swapper=new set[DEFAULT_MAX_ITEMS];
maxsize=DEFAULT_MAX_ITEMS;
}
set::set(int x)
:counter(0),m_size(0),flag(0)
{
m_set=new set[x];
swapper=new set[x];
maxsize=x;
}
void set::swap(set& other)
{
// Exchange the contents of this set with the other one.
int tempmaxsize=maxsize;
int tempcounter=counter;
int tempmsize=m_size;
swapper=m_set;
m_set=other.m_set;
other.m_set=swapper;
m_size=other.m_size;
counter=other.counter;
maxsize=other.maxsize;
other.counter=tempcounter;
other.m_size=tempmsize;
other.maxsize=tempmaxsize;
}
private:
struct set
{
ItemType entry;
int count;
};
int maxsize;
set* m_set;
int m_size;
int counter;
int flag;
set* swapper;
error code is this:
debug assertion failed!
expression:_block_type_is_valid(phead->nblockuse)
Actually changing array sizes should be part of the swap function and so should be done in a class method. As it is a class method, it has access to private members.
this is for an assignment so I will be deliberately general. My question is related to implementation decisions I already made--maybe they weren't good ones.
I have a list of pointers to structs, e.g. list<MyStruct*> bob; At one point I've needed to sort these pointers by one of the data members of their targets and I was able to do that easily with
bool sortbyarrival(const MyStruct* a, const MyStruct* b) {
return a->arrival < b->arrival;
}
And then calling bob.sort(sortbyarrival); Works great.
Now somewhere else I need to sort by a different criterion, which involves a counter in the program. I need something like return counter*a->arrival < counter*b->arrival; But the way I just described is the only way I know how to do a sort, I think, and I don't know how to pass my counter as an additional argument. How can I sort this list of pointers?
ETA: The counter is just a variable in main. So ideally I could call something like bob.sort(sortbyratio, counter); or sort(bob.begin(), bob.end(), sortbyratio, counter);
Similar to ltcmelo's example, but if the objects themselves don't contain the counter:
struct sort_with_counter {
sort_with_counter(const double d): counter(d) {}
bool operator()(const MyStruct* a, const MyStruct* b) {
return(counter*a->arrival < counter*b->arrival);
}
const double counter;
};
mylist.sort(sort_with_counter(5.0));
If your counter is an external variable like that though it won't affect the ordering (at least if it's positive - thanks onebyone!) - so this may in fact not be necessary at all (or maybe I misunderstand what you're after?). It's a useful technique in other cases though.
Create a functor, and store the extra value in the functor object:
struct CompareByCounter {
CompareByCounter(int c) : counter(c) {}
bool operator()(const MyStruct *lhs, const MyStruct *rhs) {
return (counter * lhs->arrival) < (counter * rhs->arrival);
}
private:
int counter;
};
// sort ascending
bob.sort(CompareByCounter(1));
// sort descending
bob.sort(CompareByCounter(-1));
Just create an function-object, a class/struct with an overload of operator() that does the right thing for you. In this case, taking into consideration the extra variables. Then, you pass an instance of it to the sort method.
struct my_comparison : binary_function<MyStruct const*, MyStruct const*, bool>
{
bool operator()(MyStruct const* a, MyStruct const* b)
{
return (a->counter * a->arrival) < (b->counter * b->arrival);
}
};
//Use it this way.
my_comparison comp;
//Set the arrival and counter data in instance comp.
/* ... */
//Now, pass it to the list.
bob.sort(comp);
EDIT: I just noticed that you have a list of pointers so I changed a bit the struct.