How to create a vector of class objects - c++

I'm trying to create a vector that contains various class times. Afterwards, I would compare these times to see which one is earlier through a sorting function.
Edit: after some people mentioned, I do wish to do this with an older version of C++ (prior to 11) because it's what my instructor requested
Would there be a way to do this with push_back?
So far, I have this in my main file:
std::vector<Time> times (Time t1(4,5,4), Time t2(3,5,4));
std::sort(times.begin(), times.end(), IsEarlierThan);
and this in my Time.cpp file:
#include <iostream>
#include "Time.h"
Time::Time() {
hour = 0;
minute = 0;
second = 0;
}
Time::Time(int theHour, int theMinute, int theSecond) {
hour = theHour;
minute = theMinute;
second = theSecond;
}
int Time::getHour() const {
return hour;
}
int Time::getMinute() const {
return minute;
}
int Time::getSecond() const {
return second;
}
bool IsEarlierThan(const Time& t1, const Time& t2){
if (t1.getHour() < t2.getHour()) return true;
else if (t1.getHour() == t2.getHour()){
if (t1.getMinute() < t2.getMinute()) return true;
else if (t1.getMinute() == t2.getMinute()){
if(t1.getSecond() < t2.getSecond()) return true;
}
}
return false;
}
The vector declaration is not correct, so my question would be how would I add these times (including hour, minute, and second) as separate vector values and compare them to each other (eg is 17:23:56 earlier than 19:49:50).
The IsEarlierThan function works, though I am unsure of how to implement it with a vector.
Thanks for any help!

Vector declaration is correct, vector construction is incorrect.
std::vector does not have a constructor which accepts two arguments of vector's element type.
If you want to initialize vector with the values from your code - change this line to:
std::vector<Time> times {Time(4,5,4), Time(3,5,4)};
See list initialization for detailed explanation how it works under the hood.
Edit:
For earlier than C++11 stardard - see this post.
Or if you don't care about this explicitly to be a single-statement assingment - just use push_back:
std::vector<Time> times; // create an empty vector
times.push_back(Time(4,5,4)); // append element to vector
times.push_back(Time(3,5,3));

Related

Trouble checking if item in map "binary '<': 'const_Ty' does not define this operator or a conversion to a type acceptable to the predefined operator" [duplicate]

I was working with the std::map library and I am trying to put a bunch of data into a map, I created a map to hold a date(time_t) and a float but when I try to add them in, my complier tells me "error: no match for 'operator<' (operand types are const &date, const &date)"
I tried creating an overloaded < operator, but still gave me the same error. I also tried to create a map outside of this program, and that did not need an operator< so how do I write this, and why is it even necessary?
here is the class that I am running it in:
class MutualFund
{
private:
std::string ticker;
Date oldestDate; //optional
Date newestDate; // optional
float newestNav; //optional
map<Date,float> navHistory;
set<Dividend> divHistory;
public:
MutualFund(string i)
{
if( i == "VTSMX")
{
ifstream temp;
string cell,cell2,tempstring;
int i = 1;
float tempFloat;
temp.open("C:\\Users\\Lukas PC\\Desktop\\ass6files\\VTSMXshuffled.csv");
//what needs to be done here:
// turn the cell 1 into a Date object by turning it into a time_t
//turn the cell2 into a float
//populate the map
while(!temp.eof())
{
// get the numbers from the spreadsheet
getline(temp,cell,',');
getline(temp,cell2,',');
getline(temp,tempstring);
//make a time_t object from cell and put it into a Date object
struct std::tm tm = {0};
std::istringstream ss(cell.c_str());
ss >> std::get_time(&tm, "%Y-%m-%d");
//tm.tm_mday = (tm.tm_mday -1);
std::time_t time = mktime(&tm);
Date mapDate;
mapDate.setDate(time);
//turn cell2 into a float
if(isalpha(cell.at(1)) && isalpha(cell2.at(1)))
{
}
else
{
cell2.erase(5,20);
//cout << cell2<< endl;
std::string::size_type sz;
tempFloat = stof(cell2,&sz);
navHistory[mapDate] = tempFloat;
}
i++;
}
}
else if (i == "VFINX")
{
}
}
friend const bool operator< ( const Date &lhs ,const Date &rhs)
{
return true;
}
};
Thanks for your help! always appreciated.
The reason std::map requires a less than operator is because it is implemented as a red black tree. Not only that, but the elements in a map are guaranteed to be ordered. Thus, it requires that the type it is referencing as the key be comparable via operator<.
If you don't need the elements to be ordered then you could use std::unordered_map. However, for user defined types you would have to explicitly define and overload std::hash.
With just one of operators overloaded it can determine if one is greater or if they are both equal.
Anyways, the issue with your code is the fact that you are trying to create the less than operator outside the main class. Move the overloaded operator< inside of the Date class and it should work.

why does std::map need an operator< and how do I write one

I was working with the std::map library and I am trying to put a bunch of data into a map, I created a map to hold a date(time_t) and a float but when I try to add them in, my complier tells me "error: no match for 'operator<' (operand types are const &date, const &date)"
I tried creating an overloaded < operator, but still gave me the same error. I also tried to create a map outside of this program, and that did not need an operator< so how do I write this, and why is it even necessary?
here is the class that I am running it in:
class MutualFund
{
private:
std::string ticker;
Date oldestDate; //optional
Date newestDate; // optional
float newestNav; //optional
map<Date,float> navHistory;
set<Dividend> divHistory;
public:
MutualFund(string i)
{
if( i == "VTSMX")
{
ifstream temp;
string cell,cell2,tempstring;
int i = 1;
float tempFloat;
temp.open("C:\\Users\\Lukas PC\\Desktop\\ass6files\\VTSMXshuffled.csv");
//what needs to be done here:
// turn the cell 1 into a Date object by turning it into a time_t
//turn the cell2 into a float
//populate the map
while(!temp.eof())
{
// get the numbers from the spreadsheet
getline(temp,cell,',');
getline(temp,cell2,',');
getline(temp,tempstring);
//make a time_t object from cell and put it into a Date object
struct std::tm tm = {0};
std::istringstream ss(cell.c_str());
ss >> std::get_time(&tm, "%Y-%m-%d");
//tm.tm_mday = (tm.tm_mday -1);
std::time_t time = mktime(&tm);
Date mapDate;
mapDate.setDate(time);
//turn cell2 into a float
if(isalpha(cell.at(1)) && isalpha(cell2.at(1)))
{
}
else
{
cell2.erase(5,20);
//cout << cell2<< endl;
std::string::size_type sz;
tempFloat = stof(cell2,&sz);
navHistory[mapDate] = tempFloat;
}
i++;
}
}
else if (i == "VFINX")
{
}
}
friend const bool operator< ( const Date &lhs ,const Date &rhs)
{
return true;
}
};
Thanks for your help! always appreciated.
The reason std::map requires a less than operator is because it is implemented as a red black tree. Not only that, but the elements in a map are guaranteed to be ordered. Thus, it requires that the type it is referencing as the key be comparable via operator<.
If you don't need the elements to be ordered then you could use std::unordered_map. However, for user defined types you would have to explicitly define and overload std::hash.
With just one of operators overloaded it can determine if one is greater or if they are both equal.
Anyways, the issue with your code is the fact that you are trying to create the less than operator outside the main class. Move the overloaded operator< inside of the Date class and it should work.

remove_if erases everything from vector

I'm writing a program for an assignment - it's supposed to be a database
for information about employees in a company. Basically, a vector containing
structures (individual employees).
The trouble I'm having is that remove_if erases everything from the vector - instead of an individual employee.
If I understood documentation/other topics correctly, that function should
do two things - rearrange elements of the vector, and return an
iterator to the first element outside the new range - but it doesn't do
it, it returns an iterator to the first element - and so when the
erase() function is called, all elements are deleted. At least
that's what I found when debugging it.
Here's a mcve of my code:
#include <iostream>
#include <vector>
#include <algorithm>
struct employee {
int number;
};
int main()
{
//creating the vector and adding some values to it
employee one{ 1 };
employee two{ 2 };
employee three{ 3 };
std::vector <employee> staff{ one, two, three };
int m = 2; //some parameter I want to pass to lambda function
auto it = std::remove_if(staff.begin(), staff.end(),
[m](employee a) {
if (a.number == 2)
return true; }
);
staff.erase(it, staff.end());
for (auto it = staff.begin(); it != staff.end(); it++)
std::cout << it->number << std::endl;
system("pause");
return 0;
}
I realise that I could've done the same thing in a loop - in fact, I did, but I just can't wrap my head around why doesn't this approach work. Also, a list would've probably been a better choice for this program (with it, the for loop would have taken fewer instructions to compute), but I've already finished the program, and right now I just really want to know why didn't remove_if work.
Thanks!
EDIT: As #drescherjm pointed out, that was due to the fact that the lambda function didn't return false when the when the if statement wasn't met.
So the question is answered.
The main problem is you are not returning a value when your condition in your lambda is not met. This is undefined behavior not to return a value.
auto it = std::remove_if(staff.begin(), staff.end(),
[m](employee a) {
if (a.number == 2)
return true; }
);
A simple solution is to remove the if and just return the conditional.
auto it = std::remove_if(staff.begin(), staff.end(),
[m](employee a) {
return (a.number == 2);
}
);
However as #killzonekid mentioned this is not correct because you are still not using the parameter.
auto it = std::remove_if(staff.begin(), staff.end(),
[m](employee a) {
return (a.number == m);
}
);
Replacing the fixed 2 with m should take care of that.

c++ stl priority queue constructors

I wrote the following code to take in many inputs and then output them in a specific order.
#DEFINE cases 100
struct job
{
int w;
};
class compjob
{
public:
bool operator()( job j1,job j2)
{
if(j2.w>j1.w)
return true;
return false;
}
};
int main()
{
priority_queue< job, vector<job>, compjob > jobs;
int weight;
for(int i=1;i<=cases;i++)
{
cin>>weight;
job job1;
job1.w=weight;
jobs.push(job1);
} //for loop ends here
for(int i=1;i<=cases;i++)
{
job job1= jobs.pop(); ////////////ERROR!!!!!/////////
cout<<job1.w<<endl;
}
return 0;;
}
But when I compile the code, a compile error is displayed on the line marked above:
Invalid conversion from 'void' to non scalar 'job'.
I think that I didn't declare jobs priority_queue correctly. Also, please explain the significance of second argument in the declaration(i.e. vector, I don't really know its use)
pop does not return anything, use top first to get the element and then pop it.
I'll recommend you to see the help page C++ reference: priority_queue , everytime you're using a library.
Some guy might say cpluplus contains some errors, so you can try this as an alternative.

Double map insertion problem

I have an
stl::map that has the key defined as an object I defined, and int. The use of the map is as follows:
I have a list of the specific object and I want to count how many identical objects I have. So I insert the objects into the map.if the object already exists in the map I increase it's value (hence the counter). The object has all the basic operators defined. The object consist of 5 strings. The == operator defined as the comparison of all 5 strings, and logically is meaningfull in the context. The problem is that the operator < has no logic meaning in the context. I care only if the objects are equal. I can't define which of two different objects is bigger.so for the sake of stl map defined this operator as the result of if else ladder and in each if I compared with "<" another string of the five. If true return true else, if.... And the last else returns false. In a specific case of the object , where I had three identical instances, I got the map containing two identical objects as keys, one of them had the counter of 1 and the other had 2.
i can't understand what is the problem and how could it happen.
For those who requested some code examples - for reason i can't explain - i can't post the code itself, but i will write a good example of it(please ignore little things like missing ';' - i wrote it in 5 minutes):
class Example
{
private:
string one;
string two;
string three;
string four;
string five;
public:
inline Example (string a_one,string a_two, string a_four, string a_five) :
one(a_one),two(a_two),three(a_three),four(a_four),five(a_five)
{}
inline bool operator == (const Example& other) const
{
if (one == other.one)
{
if (two == other.two)
{
if (three == other.three)
{
if (four == other.four)
{
if (five == other.five)
{
return true;
}
}
}
}
}
return false;
}
inline bool operator < (const Example& other) const
{
if (one < other.one)
{
return true;
}
else if (two < other.two)
{
return true;
}
else if (three < other.three)
{
return true ;
}
else if (four < other.four)
{
return true;
}
else if (five < other.five)
{
return true;
}
else
{
return false;
}
}
}
void CountExample(Example& example,std::map<Example,int>& counters);
void main()
{
std::map<Example,int> counters;
std::list<Example> examples = GetExamples();
//GetExamples defined elsewhere, and initializes examples with a long list of instances of Example
std::list<Example>::const_iterator Iter;
for (Iter = examples.begin();Iter != examples.end();Iter++)
{
CountExample(*Iter);
}
PrintCounters(counters);//PrintCounters defined elsewhere and prints the map to a file
}
void CountExample(Example& example,std::map<Example,int>& counters)
{
std::map<Example,int>::const_iterator Iter;
Iter = counters.find(example);
if (Iter ==counters.end()) //means the specific Example is not in the map
{
counters.insert(std::pair<Example,int>(example,1));
}
else
{
counters[example] += 1;
{
}
If you have a reasonably modern compiler, that ladder of comparisons can be replaced with a single comparison between two std::tie()'d tuples:
#include <tuple>
...
bool operator== (const Example& other) const
{
return std::tie(one, two, three, four, five)
== std::tie(other.one, other.two, other.three, other.four, other.five);
}
bool operator < (const Example& other) const
{
return std::tie(one, two, three, four, five)
< std::tie(other.one, other.two, other.three, other.four, other.five);
}
Incidentally, it may be simpler to use a std::multiset to count the number of times a particular element is stored in an associative container, that simplifies CountExample to a one-liner
void CountExample(const Example& example, std::multiset<Example>& counters)
{
counters.insert(example);
}
Although printing becomes a bit more tricky:
void PrintCounters(const std::multiset<Example>& counters)
{
for(auto i=counters.begin(); i!=counters.end(); i = counters.upper_bound(*i))
std::cout << *i << ":" << counters.count(*i) << '\n';
}
Test on ideone: http://ideone.com/uA7ao
To make a comparison with multiple elements, each element that you compare will have three outcomes: less than, greater than, or equivalent. You must account for all of these cases.
bool LessThan(const MyClass & left, const MyClass right)
{
if (left.one < right.one)
return true;
else if (right.one < left.one)
return false;
// equivalent in one
if (left.two < right.two)
return true;
else if (right.two < left.two)
return false;
// equivalent in one and two
...
return false;
}
You need to provide an operator< for you type. This can be pretty tedious to write, but you can simply it by using a Boost.Tuple - that way, the tuple handles the comparisons, leaving your code easier to read, write and understand.
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <string>
struct Object
{
std::string a;
std::string b;
std::string c;
};
bool operator<(const Object& obj1, const Object& obj2)
{
return (boost::tie(obj1.a, obj1.b, obj1.c) <
boost::tie(obj2.a, obj2.b, obj2.c));
}
Edit: After thinking about the problem some more, I've decided to removed my older answer since it did not seem pertinent to the current problem being experienced. Your operator< method does seem to be fulfilling the requirements for a strict weak ordering, so I think the problem lies somewhere else, and so I'm leaving the following alternate solution below ...
It seem you're having issues creating a total order for your map, so you might want to look at std::unordered_map as an alternative that will directly apply your operator== for detecting equality, rather than using your operator< for a strict weak ordering ... you'll have to provide a hash-function for your class, but otherwise the use of the hash-table based std::unordered_map container is pretty straight-forward.