If I had a program reading a file that contained something along the lines of "Boss1 Dave Jim Boss3 Coleen Boss 7 Harris Todd Elaine" and I'm trying to separate the inputs into a list of bosses and a list of names, I would check each string inputted, but how can I tell if the person is a boss or not? I would set up something like this to begin with:
void read(std::istream& is, Bosses<std::string>& bossList, Employees<std::string> empList){
std::string name;
while(!is.eof()){
is >> name;
}
}
But I would need to check in the while loop if something like name=="Boss_" but I don't understand strings well enough to know how to set this up.
You can use the insertion operator to parse the string of names as your string is whitespace delimited, and the insertion operator skips over whitespace (by default):
void read(std::istream& is, Bosses<std::string>& bossList, Employees<std::string> empList) {
std::string temp;
std::vector<std::string> all_names;
//the insertion operator reads the string and bypasses all whitespace by default
while (is >> temp) {
//find bosses by using `std::string
if (temp.find("Boss") != std::string::npos) {
boosList.push_back(temp);//you didn't state what container `Bosses` uses but, `push_back is valid for `lists`, `vectors` and `deques`
}
else {
empList.push_back(temp);//you didn't state what container `Employees` uses but, `push_back is valid for `lists`, `vectors` and `deques`
}
}
}
Related
In my class, I want the family data member to be one of the five strings in the static array fiveNewYorkFamilies[5]. I made a constructor to take input from the user and see if it corresponds to one of the elements in the array. If it does match, then I go on with my program; if not, I repeat the step using a goto. My program works fine, but there's one thing I don't understand: When I first insert the input, the variable family is empty as indicated by the empty function I put atop of it. However, if I fail to insert a correct input the first time, and continue to insert an input a second time, I am inserting an input atop the previous input. For example, if I input "Lebron" the first time and then insert "Corleone" the second time (the empty function reassures me that family is not empty), the variable family would be "LebronCorleone." In spite of this, my program works just fine. Can someone explain to me why is that? And if I'm misunderstanding the situation, can someone clear it up? Thank you.
class Godfather
{
std::string family;
public:
explicit Godfather(std::istream & is);
Godfather(): family("Corleone") {}
static std::string fiveNewYorkFamilies[5];
std::string getFamily() const {return this->family;}
};
std::string Godfather::fiveNewYorkFamilies[5] = {"Corleone", "Barzini", "Cuneo", "Stracci", "Tattaglia"};
Godfather::Godfather(std::istream & is)
{
label:
std::cout << family.empty();
is >> family;
bool match = false;
for(std::string * ptr = fiveNewYorkFamilies; ptr != fiveNewYorkFamilies + 5; ++ptr)
if(*ptr == family)
match = true;
if(!match)
goto label;
}
int main()
{
Godfather vito(std::cin);
}
You can improve the code by removing the goto label. Instead, use a while loop. When an input is correct, just return so the function ends.
Also, use a foreach loop when you parse the possible names. This way you won't care if the size of the possible names is changing (hence you won't need to change from 5 to 6, 6 to 7 etc. whenever you add a new possible name in the array).
Godfather::Godfather(std::istream& is) {
while (is >> family) {
for (const auto& possibleName : fiveNewYorkFamilies) {
if (family == possibleName)
return;
}
}
}
P.S. Good luck with your Sa:Mp server.
I create a class named Employee, in private, I have a Name as a string . here is my class declaring:
class Employee
{
string Name;
public:
Employee();
void SetName(string);
void StringToEmployee(string);
~Employee();
}
this is definition of StringToEmployee(string) method:
void Employee::StringToEmployee(string s)
{
char *first = s, *end = s+strlen(s), *last = NULL;
last = find(first, end, ',');
string temp(first, last- first);
SetName(temp);
}
The error occurs when I debug to the line string temp(first, last- first), it's seem to the compiler does not allow me to construct a new string in method. cause I have also changed into string temp; then temp.assign(first, last-first). the error still remain. How could I create a new string in a method?
You should be using iterators and taking advantage of the features of the standard library, rather than raw pointers and C-style string functions. Not only will this give you more idiomatic and easier to understand C++ code, but it will also implicitly resolve many of your errors.
First, the implementation of StringToEmployee should be rewritten as follows:
void Employee::StringToEmployee(std::string s)
{
const std::string temp(s.begin(),
std::find(s.begin(), s.end(), ',');
SetName(temp);
}
But since you are not modifying the s parameter and do not need a copy of it, you should pass it by constant reference:
void Employee::StringToEmployee(const std::string& s)
{
const std::string temp(s.begin(),
std::find(s.begin(), s.end(), ',');
SetName(temp);
}
Also, you should consider redesigning your Employee class. Currently, you have a default constructor that creates an invalid Employee object, and then you have member functions that allow you to turn that invalid Employee object into a valid one by settings its members. Instead, you could have a constructor that did all of this initialization for you, in one step. Not only would your code be cleaner and easier to understand, but it would be more efficient, too!
Perhaps something like:
class Employee
{
std::string Name; // name of this employee
public:
Employee(const std::string& name); // create Employee with specified name
void SetName(const std::string& newName); // change this employee's name
~Employee();
};
Employee::Employee(const std::string& name)
: Name(s.begin(), std::find(s.begin(), s.end(), ','))
{ }
void Employee::SetName(const std::string& newName)
{
Name = std::string(s.begin(), std::find(s.begin(), s.end(), ','));
}
Employee::~Employee()
{ }
A couple of quick notes:
You'll see that I always explicitly write out std:: whenever I use a class from the standard library's namespace. This is a really good habit to get into, and it's not really that hard to type an extra 5 characters. It's particularly important because using namespace std; is a really bad habit to get into.
I pass objects (like strings) that I don't need to modify or have a copy of inside of the method by constant reference. This is both easier to reason about, and also potentially more efficient (because it avoids unnecessary copies).
Inside of the constructor, I have used what may appear to be a funny-looking syntax, involving a colon and some parentheses. This is called a member initialization list, and it's something you should get used to seeing. It's the standard way for a class's constructor to initialize its member variables.
For some reason you want to assing std::string to char*.
Judging from other your code, you want to work with raw char array, so, you need to put correct pointers to first and last like this:
char *first = &s[0], *end = (&s[0]) + strlen(s.c_str()), *last = NULL;
And this part:
string temp(first, last- first);
is incorrect, because last - first is pointer, and, as I understand, you want to use std::string(const char*, size_t) constructor. But instead, you are using iterator-based constructor and system is correctly dying, because first pointer is larger, than second one.
As you see, your method is error-prone. I recommend re-do this part of code, using iterators, like this:
void Employee::StringToEmployee(string s)
{
auto found = find(s.begin(), s.end(), ',');
string temp(s.begin(), found);
SetName(temp);
}
I'm trying to take input from the user and the user have multiple choice to enter the different types of inputs(char, int float). And according to the value entered I have to take proper action.
eg. I have a function below :-
int* function(int data)
{
int a[50];
int k = 0;
a[k] = data;
k++;
// I want to make choice generalized so that it can accept both type of
// values int as well as char.
cout<<"\n Enter integer element to insert into array, otherwise press 'n' to terminate array list: ";
cin>>choice;
if(choice != 'n')
function(choice);
return a;
}
So, in the above example I want to make choice generalized. I how to use template for function and classes but, I want to do this for variable. Please help.
NOTE: the above code is just a example to illustrate my problem.
Thank's.
Templates are a compile time construct, so there is no way to let the user input have an influence on the template type.
What you can do is some template based automation of the input conversion where you decide which template instantiations should be checked. Suppose you have a class to handle your input conversion called GenericInput with template functions bool GenericInput::CanConvert<TargetType>() and TargetType GenericInput::Convert<TargetType>()
GenericInput in;
std::cin >> in;
if (in.CanConvert<int>()) {
// some action
}
else if (in.CanConvert<char>()) {
// another action
}
// ...
It would basically be a wrapper for the idea to first read the string and then check, how the string can be interpreted.
To implement it, you would need the following things:
Overload operator >>
std::istream& operator >>(std::istream& stream, GenericInput& element) {
/* TODO: read input into string member of GenericInput object */
return stream;
}
The GenericInput class
class GenericInput {
private:
std::string _inputElement; // store input as base for conversion
public:
// TODO: standard class implementation
template <typename TargetType>
bool CanConvert() {
// TODO: create std::stringstream from _inputElement and try to read into a TargetType variable
// return true if the stringstream is valid after the read
}
template <typename TargetType>
TargetType Convert() {
// TODO: create std::stringstream from _inputElement and try to read into a TargetType variable
// return variable if the stringstream is valid after the read, otherwise report error
}
}
Regarding the "valid" stringstream after read, it might be important to check two things: if the stringstream is in some kind of error state, conversion failed. If there are unread characters in the stringstream, the conversion was incomplete, which may also count as a failure.
Please don't expect this to be working out of the box, its more of an idea scratch than an actual implementation.
I have been asked a question in an interview and want to know program approach to solve it.
Que: We have a text file which contain operation need to be performed in a program. User can update this text file and change the operation i.e. text file can contain + for addition or - for subtraction. Program has two variable i.e. a and b, reads text file, perform operation and display result. If text file contain +, then program should return sum of a and b and if text file has - then program should return a-b. User can put any operation in text file.
I have given two approaches:
Program can have switch statement in it. If text file has +, program check switch statement and perform a+b operation as per switch statement, like wise for for other operations. This answer was rejected as we have to hard code all possible operations in switch.
I can use oracle and run query for any operation i.e. if text file has +, then I can create a sql string like 'select a+b into :result from dual;' and run an embedded sql in program. Database will execute sql and return output for any valid operation and program need not to hard code all possible operation. I have given this answer as I was giving interview for C++/C and pro*c. But panel was not satisfied with this approach also.
So what is the best approach to solve this problem through a program ?
Probably something like this, a lookup table for functions with similar prototype
int add(int a,int b)
{
return a+b;
}
int sub(int a,int b)
{
return a-b;
}
typedef int (*function_cb)(int,int);
std::map<string, function_cb> callBacks;
.....
void init_lookup()
{
callBacks["+"] = &add;
callBacks["-"] = ⊂
}
And then use it based on your text file
int res = callBacks["-"](8,4);
Where - , 8 , 4 are from your text file
For reading the expression from the input file, you can use the standard reading method that Standard Library offers:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
cout << line << '\n';
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
(code taken from cplusplus.com)
About translating that string you get from the file... you get very deep into expression trees. For working with the expression trees, you can take a look at the code below. This is something I wrote in the past to explain somebody about this concept:
class Token
{
public:
enum TokenTypes { operator_token, operand_token };
Token();
Token( std::string token );
~Token(); // we are not inheriting, so no need to be virtual
Token(const Token &in);
Token& operator=(const Token &in);
TokenTypes getId() const;
// you need to set the left/right from addToken(), see class Tree
void setLeft(Token* left);
void setRight(Token* right);
const Token* getLeft();
const Token* getRight();
private:
// when creating the Token you need to be able to identify
// what TokenType the string is
TokenTypes tokenId( std::string token );
TokenTypes m_id; // type of token
std::string m_token; // the actual string token e.g. "+", "12", ..
Token* m_left; // the pointers to the children left or right in a binary tree
Token* m_right;
};
class Tree
{
public:
Tree();
~Tree(); // clean up
void addToken( std::string token ); // this adds a token to the tree
private:
Token* m_root;
};
you can then use it like so...
std::string strToken
Tree T;
while ( getNextStringToken(strToken) )
{
Token* newToken = new Token(strToken);
T.addToken(newToken);
}
You can read more about this concept on Wikipedia.
I hope this helps you!
In my opinion They just want to read the character +,-,* and put this character in between the variables and execute the statement.
for how to convert the string into expression see this answerConvert string to mathematical evaluation
I think this questions is more along the lines of operator overloading, you can define what normal operators would do when the operands are functions/other than standard variables.
I need to implement a mechanism where I can initialize a vector of my custom class using a text source, where each line of the source is representing one instance of my class. To achieve this, I implemented the operator >> for my class and stringstream. When I read the source, I go line-by-line and get a substream of my original source, then parse the substream each time. This has three benefits for me. First, this way I can make sure that one line of the text source would represent exactly one instance of my class. Second, as the rest of the line after parsing is ignored, I can safely add any comment in any line of my text source, which would surely get ignored by the parser. And third, I don't need to mention the length of the vector in my original source, since the first time I get a parsing error (I check the fail and bad bits of the stream to confirm this) I know that the vector declaration is over.
To parse line-by-line, I'm using the following code:
std::stringstream fullStream;
std::stringstream lineStream;
std::string str;
bool isValid;
myClass newInstance;
std::vector < myClass > result;
// Fill fullStream from external source (codepart omitted)
isValid = true;
while ( isValid && ! fullStream.eof ( ) ) {
std::getline ( fullStream, str );
lineStream.clear ( );
lineStream.str ( str );
lineStream >> newInstance;
isValid = ! lineStream.fail ( );
if ( isValid ) {
result.push_back ( newInstance );
}
}
Although this code works fine, I'm wondering if there was a better way to achieve the same result. Specially, if there was a more efficient way to extract a line from fullStream to lineStream.
Thanks,
Ádám
First, if the code works, it is really only by chance. The idiomatic
way of handling this is:
std::string line;
while ( std::getline( fullStream, line ) ) {
std::istringstream lineStream( line );
lineStream >> newInstance;
if ( lineStream ) {
result.push_back( newInstance );
} else {
fullStream.setstate( std::ios_base::failbit );
}
}
Checking eof() before a read is rarely useful, and not checking the
results of your getline before using it is almost certainly an error.
Trying to reuse a stringstream is more complex and error prone than
simply creating a new one; there is all sorts of state which may or may
not have to be reset. Streams have a mechanism for memorizing error
state, so you probably want to use this. (If you want to continue using
fullStream for other things after the error, the problem is more
complex, because you've already extracted the line which failed, and you
can't put it back.) And if you're only reading, you should use
std::istringstream, and not std::stringstream (which has a lot of
extra baggage); in general, it's very, very rare to use a bi-directional
stream.
One obvious alternative would be to have your operator>> do line-by-line reading itself, so you don't have to do that externally:
class MyClass {
// some sort of data to demonstrate the idea:
int x;
std::string y;
friend std::istream &operator>>(std::istream &is, MyClass &m) {
std::string temp;
std::getline(is, temp);
std::istringstream buffer(temp);
buffer >> m.x >> m.y;
return is;
}
};
With that, code to read data from a file becomes a little more straightforward:
std::copy(std::istream_iterator<MyClass>(fullStream),
std::istream_iterator<MyClass>(),
std::back_inserter(result));
Edit: if you don't want to build the line-oriented reading directly into the operator>> for MyClass, another possibility is to use a proxy class:
class LineReader {
MyClass object;
public:
operator MyClass() { return object; }
friend std::istream &operator>>(std::istream &is, LineReader &d) {
std::string line;
std::getline(is, line);
std::istringstream buffer(line);
buffer >> d; // delegate to the object's own stream-oriented reader.
}
};
Then when you want to do line-oriented reading, you read objects of the proxy class, but store objects of the original class:
std::vector<MyClass>((std::istream_iterator<LineReader>(some_stream)),
std::istream_iterator<LineReader>());
But, when/if you want to read a stream of objects instead of lines of objects, you use the object's own operator>> directly:
std::vector<MyClass>((std::istream_iterator<MyClass>(stream),
std::istream_iterator<MyClass>());