I have a program that take commands from user and it will process different commands differently. For example:
ADD_STUDENT ALEX 5.11 175
ADD_TEACHER MERY 5.4 120 70000
PRINT MERY
REMOVE ALEX
PRINT TEACHER SALARY
PRINTALL
therefore, I need to examine each line and see what is the input consists of.
Here is my code, but I think I misunderstand the way iss<< work. Can someone give me a suggestion? And tell me how why my code didn't work as I expected?
string line;
while(getline(cin, line))
{
//some initialization of string, float variable
std::istringstream iss(line);
if(iss >> command >> name >> height >> weight)
..examine the command is correct(ADD_STUDENT) and then do something..
else if(iss >> command >> name >> height >> weight >> salary)
..examine the command is correct(ADD_TEACHER) and then do something...
else if(iss >> command >> name)
..examine the command is correct(REMOVE) and then do somethin...
}
My thought is that the iss>> first >>second >> third will return true if all arguments are filled and false if not enough arguments. But apparently I am wrong.
Answer: In C++/C user can take multiple inputs in one line using scanf but in Python user can take multiple values or inputs in one line by two methods.
Using split() method : This function helps in getting a multiple inputs from user. It breaks the given input by the specified separator. If a separator is not provided then any white space is a separator. Generally, user use a split() method to split a Python string but one can use it in taking multiple input.
Using split() method This function helps in getting multiple inputs from users. It breaks the given input by the specified separator. If a separator is not provided then any white space is a separator. Generally, users use a split() method to split a Python string but one can use it for taking multiple inputs.
Your problem was deliciously underspecified. This always prompts me to supply an overblown example implementation using Boost Spirit.
Note: just don't hand this in as your homework assignment, please.
See it Live on Coliru with the following sample input:
ADD_STUDENT ALEX 5.11 175
ADD_STUDENT PUFF 6 7
ADD_STUDENT MAGIC 7 8
ADD_STUDENT DRAGON 8 9
ADD_TEACHER MERY 5.4 120 70000
PRINT MERY
ADD_TEACHER DUPLO 5.4 120 140000
PRINTALL 10
REMOVE ALEX
PRINT TEACHER SALARY
PRINT MERY PUFF MAGIC DRAGON
REMOVE MERY PUFF MAGIC DRAGON
PRINT TEACHER SALARY
Full code:
Update When including make_visitor.hpp
as shown here you can write the visitor code more elegantly:
auto print_salary = [&] ()
{
for(auto& p : names)
boost::apply_visitor(make_visitor(
[](Teacher const& v) { std::cout << "Teacher salary: " << v.salary << "\n"; },
[](Student const& v) {}),
p.second);
};
See adapted example Live on Coliru
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx= boost::phoenix;
struct Person
{
std::string name;
double height, weight;
friend std::ostream& operator<<(std::ostream& os, Person const& s) {
return os << "Person { name:" << s.name << ", height:" << s.height << ", weight:" << s.weight << " }";
}
};
struct Student : Person
{
Student() = default;
Student(std::string n, double h, double w) : Person {n,h,w} {}
};
struct Teacher : Person
{
Teacher() = default;
Teacher(std::string n, double h, double w, double s) : Person {n,h,w}, salary(s) {}
double salary;
};
int main()
{
std::stringstream ss;
ss << std::cin.rdbuf();
std::map<std::string, boost::variant<Student, Teacher> > names;
using namespace qi;
auto add_student = phx::ref(names)[_1] = phx::construct<Student>(_1, _2, _3);
auto add_teacher = phx::ref(names)[_1] = phx::construct<Teacher>(_1, _2, _3, _4);
auto remove = phx::erase(phx::ref(names), _1);
auto print_all = [&] (int i) { for(auto& p : names) { std::cout << p.second << "\n"; if (--i==0) break; } };
auto print_salary = [&] ()
{
struct _ : boost::static_visitor<> {
void operator()(Teacher const& v) const { std::cout << "Teacher salary: " << v.salary << "\n"; }
void operator()(Student const& v) const { }
} v_;
for(auto& p : names) boost::apply_visitor(v_, p.second);
};
auto name_ = as_string[lexeme[+graph]];
if (phrase_parse(begin(ss.str()), end(ss.str()),
(
("ADD_STUDENT" >> name_ >> double_ >> double_) [ add_student ]
| ("ADD_TEACHER" >> name_ >> double_ >> double_ >> double_) [ add_teacher ]
| (eps >> "PRINT" >> "TEACHER" >> "SALARY") [ print_salary ]
| ("PRINTALL" >> int_) [ phx::bind(print_all, _1) ]
| ("PRINT" >> +name_ [ std::cout << phx::ref(names)[_1] << std::endl ])
| ("REMOVE" >> +name_ [ remove ])
) % +eol,
qi::blank))
{
std::cout << "Success";
}
else
{
std::cout << "Parse failure";
}
}
Output:
Person { name:MERY, height:5.4, weight:120 }
Person { name:ALEX, height:5.11, weight:175 }
Person { name:DRAGON, height:8, weight:9 }
Person { name:DUPLO, height:5.4, weight:120 }
Person { name:MAGIC, height:7, weight:8 }
Person { name:MERY, height:5.4, weight:120 }
Person { name:PUFF, height:6, weight:7 }
Teacher salary: 140000
Teacher salary: 70000
Person { name:MERY, height:5.4, weight:120 }
Person { name:PUFF, height:6, weight:7 }
Person { name:MAGIC, height:7, weight:8 }
Person { name:DRAGON, height:8, weight:9 }
Teacher salary: 140000
Success
Do it like so:
iss >> command;
if (!iss)
cout << "error: can not read command\n";
else if (command == "ADD_STUDENT")
iss >> name >> height >> weight;
else if (command == "ADD_TEACHER")
iss >> name >> height >> weight >> salary;
else if ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With