I have created a program, which requires user to define at least 2 arguments(3rd is optional). Arguments are:
- Command(string type)
- Date(custom type/class)
- Event(string type) - Optional.
I have come up with the following idea:
int main() {
Database db /*my custom class */
string command;
vector<string> arguments;
while (getline(cin, command, ' ')) {
arguments.push_back(command);
}
and after that the idea was to use indexing for arguments:
if(arguments[0] == "Add"){
Date date arguments[1];
db.Add(date,arguments[2])
}
} else if(arguments[0] == "Find"){
Date date = arguments[1];
db.Find(date);
But unfortunately, Date date = arguments[1];
doesn't work. How can I handle a problem of user input arguments with different data types, with one argument optional.
Here is my Date class:
class Date {
public:
Date(){
};
Date(int new_year, int new_month, int new_day){
if(new_month > 12 || new_month < 1){
throw invalid_argument("Month value is invalid: " to_string(new_month));
} else if (new_day > 31 || new_day < 1){
throw invalid_argument("Day value is invalid: " to_string(new_day));
}
year = new_year;
month = new_month;
day = new_day;
}
int GetYear() const{
return year;
};
int GetMonth() const{
return month;
};
int GetDay() const{
return day;
};
private:
int year;
int month;
int day;
};
bool operator<(const Date& lhs, const Date& rhs){
if(lhs.GetYear() != rhs.GetYear()){
return (lhs.GetYear() - rhs.GetYear()) < 0;
} else if(lhs.GetMonth() != rhs.GetMonth()){
return (lhs.GetMonth() - rhs.GetMonth()) < 0;
} else {
return (lhs.GetDay() - rhs.GetDay()) < 0;
}
};
bool operator>(const Date& lhs, const Date& rhs){
if(lhs.GetYear() != rhs.GetYear()){
return (lhs.GetYear() - rhs.GetYear()) > 0;
} else if(lhs.GetMonth() != rhs.GetMonth()){
return (lhs.GetMonth() - rhs.GetMonth()) > 0;
} else {
return (lhs.GetDay() - rhs.GetDay()) > 0;
}
};
bool operator==(const Date& lhs, const Date& rhs){
if(lhs.GetYear() == rhs.GetYear() && lhs.GetMonth() == rhs.GetMonth() && lhs.GetDay() == rhs.GetDay()){
return true;
}
return false;
};
ostream& operator<<(ostream& stream, const Date& date){
stream << date.GetYear() << '-' << date.GetMonth() << '-' << date.GetDay();
return stream;
}
istream& operator>>(istream& stream, Date& d) { //возвращать будем ссылку на поток
//if (stream) return stream;
int year,month,day;
char c;
stream >> year >> c >> month >> c >> day;
if (stream && c == '-')
d = Date(year,month,day);
return (stream);
}
CodePudding user response:
But unfortunately,
Date date = arguments[1];
doesn't work.
Correct, because arguments[1]
is a std::string
, but Date
does not have a constructor that accepts a std::string
. So add one, eg:
class Date {
public:
Date() {
setDate(0, 1, 1);
};
Date(int new_year, int new_month, int new_day) {
setDate(new_year, new_month, new_day);
}
Date(const string &str) {
int new_year, new_month, new_day;
// parse str to extract new_year, new_month, new_day as needed...
setDate(new_year, new_month, new_day);
}
void setDate(int new_year, int new_month, int new_day) {
if(new_month > 12 || new_month < 1){
throw invalid_argument("Month value is invalid: " to_string(new_month));
} else if (new_day > 31 || new_day < 1){
throw invalid_argument("Day value is invalid: " to_string(new_day));
}
year = new_year;
month = new_month;
day = new_day;
}
...
};
There are many ways to parse a string to extract sub values. For instance, you can use:
string::find()
string::substr()
std::stoi()
std::istringstream
operator>>
std::sscanf()
std::regex
- etc
Use whatever you are most comfortable with. Just for demonstration purposes, let's use std::sscanf()
:
#include <cstdio>
class Date {
public:
...
Date(const string &str) {
int new_year, new_month, new_day;
if ((sscanf(str.c_str(), "M----", &new_year, &new_month, &new_day) != 3) &&
(sscanf(str.c_str(), "M/-/-", &new_year, &new_month, &new_day) != 3)) {
throw invalid_argument("Str value is invalid: " str);
}
setDate(new_year, new_month, new_day);
}
...
};
On a side note, you might consider using command-line arguments instead of input I/O, eg:
int main(int argc, const char* argv[]) {
...
vector<string> arguments;
for (int i = 1; i < argc; i) {
arguments.push_back(argv[i]);
}
...
}
And then users can call your program like this:
program.exe command date event
Instead of running program.exe
first and then entering command
, date
, and event
separately.
CodePudding user response:
Date date = <whatever>
calls a constructor (like Date date(<whatever>);
). I do not see a constructor for Date
that takes a string.
This notation is only available for constructors that have one argument.
Generally =
is an assignment operator call, or sometimes a constructor call (namely, when you declare a variable like in Date date = ...;
as opposed to Date date; date = ...;
– this would be an assignment operator call).
You can write Date date(int1, int2, int3);
where the int
s are obviously some int
s retrieved from the input. You have to either give it 3 int
s (as you have in the constructor) – or else, to make the main()
code simpler, write a constructor taking a string and retrieve int
s from the string.