I'm currently trying to copy a vector to a new text file after making the necessary changes to the vector. I can build the project fine, but its giving me weird errors that I don't understand. Could anyone possibly help me with this?
My struct
class AccDetails {
public:
string username;
string name;
string topicid;
string testid;
};
The code that is giving me the errors
vector<AccDetails>accInfo;
ofstream temp ("temp.txt");
ostream_iterator<AccDetails>temp_itr(temp,"\n");
copy(accInfo.begin(),accInfo.end(),temp_itr);
There's a whole chunk of error lines, but i think this should be the important 2 lines:
You'll need to overload operator<< for AccDetails. It is what ostream_iterator calls internaly.
Something like this:
std::ostream& operator<<(std::ostream& stream, const AccDetails& obj)
{
// insert objects fields in the stream one by one along with some
// description and formatting:
stream << "User Name: " << obj.username << '\n'
<< "Real Name: " << obj.name << '\n'
<< obj.topicid << ' ' << obj.testid << '\n';
return stream;
}
The operator takes the stream it inserts to as first parameter and a constant reference to the object it is streaming as the second one (this allows passing temporary AccDetails, too). Now you can also say:
AccDetails acc;
std::cout << acc;
If the operator would need access to AccDetail's private fields, you would need to declare as a friend.
If you're new to operator overloading, I suggest you read this SO thread.
Hope that helps.
Can have this after overloading as jrok said:
class AccDetails
{
std::string username;
std::string name;
std::string topicid;
std::string testid;
friend std::ostream& operator<<(std::ostream&, const AccDetails&);
friend std::istream& operator>>(std::istream& is, AccDetails& );
};
std::ostream& operator<<(std::ostream& os, const AccDetails& acc)
{
os << "User Name: " << acc.username << std::endl
<< "Name: " << acc.name << std::endl
<< acc.topicid << ' ' << acc.testid << std::endl;
return os;
}
std::istream& operator>>(std::istream& is, AccDetails& acc)
{
is >> acc.username >>acc.name >> acc.topicid >> acc.testid ;
return is;
}
int main()
{
std::vector<AccDetails>accInfo;
std::copy(std::istream_iterator<AccDetails>(std::cin),
std::istream_iterator<AccDetails>(),std::back_inserter(accInfo) );
std::ofstream temp("temp.txt",std::ios::out);
std::ostream_iterator<AccDetails>temp_itr(temp,"\n");
std::copy(accInfo.begin(),accInfo.end(),temp_itr);
}
Related
I'm working on boost::asio::streambuf and found out that I can send/get a struct using it, but when I send a struct I just can't get it as I have sent it. The documentation says that one should use commit() and consume(), but where should I use them here?
struct person
{
int m_id;
std::string m_message;
};
std::istream& operator>>(std::istream& in, struct person& p)
{
return in >> p.m_id >> p.m_message;
}
std::ostream& operator<<(std::ostream& out, struct person& p)
{
return out << p.m_id << " " << p.m_message;
}
int main()
{
boost::asio::streambuf buf;
std::ostream out(&buf);
person p;
p.m_id = 1;
p.m_message = "Hello World!";
out << p;
std::istream in(&buf);
person p1;
in >> p1;
cout << "ID: " << p1.m_id << endl;
cout << "Message: " << p1.m_message << endl;
return 0;
}
The problem is with strings so when I type only "hello" (without world), it works fine, but if I add "world!" as shown above it just doesn't see the added "world!", why?
There are a number of issues.
Firstly, make the arguments const& when possible:
std::ostream &operator<<(std::ostream &out, person const &p) {
Secondly, make sure the streams flush to the buffer. I think it's good practice to limit the lifetime of the ostream or istream instances
Thirdly, choose a format that will be robust. Your sample already had bigger problems, when you had m_id = 1 and m_message = "123" (can you see it?).
In text formats you need either fixed-length fields or a delimiting protocol. Let's fix it:
std::ostream &operator<<(std::ostream &out, person const &p) {
return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message;
}
Now when reading it back you will see how much more precise you need to be:
std::istream &operator>>(std::istream &in, person &p) {
char separator;
size_t length;
bool ok = in >> p.m_id
&& in >> separator && separator == ';'
&& in >> length
&& in >> separator && separator == ';'
;
if (ok) {
p.m_message.resize(length);
in.read(&p.m_message[0], length);
p.m_message.resize(in.gcount());
}
// ensure the expected number of bytes were read
ok = ok && (p.m_message.length() == length);
if (!ok)
in.setstate(std::ios::failbit);
return in;
}
Yikes. Really? Yes really. At a minimum!
Do error handling
Full Demo
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
struct person {
int m_id;
std::string m_message;
};
std::ostream &operator<<(std::ostream &out, person const &p) {
return out << p.m_id << ";" << p.m_message.length() << ";" << p.m_message;
}
std::istream &operator>>(std::istream &in, person &p) {
char separator;
size_t length;
bool ok = in >> p.m_id
&& in >> separator && separator == ';'
&& in >> length
&& in >> separator && separator == ';'
;
if (ok) {
p.m_message.resize(length);
in.read(&p.m_message[0], length);
p.m_message.resize(in.gcount());
}
// ensure the expected number of bytes were read
ok = ok && (p.m_message.length() == length);
if (!ok)
in.setstate(std::ios::failbit);
return in;
}
int main() {
boost::asio::streambuf buf;
std::ostream(&buf) << person{ 1, "Hello World!" };
person received;
if (std::istream(&buf) >> received) {
std::cout << "ID: " << received.m_id << std::endl;
std::cout << "Message: " << received.m_message << std::endl;
} else {
std::cout << "Couldn't receive person\n";
}
}
Prints
ID: 1
Message: Hello World!
BONUS
C++14 added std::quoted:
#include <iomanip>
std::ostream &operator<<(std::ostream &out, person const &p) { return out << p.m_id << std::quoted(p.m_message); }
std::istream &operator>>(std::istream &in, person &p) { return in >> p.m_id >> std::quoted(p.m_message); }
Which, in this case, also does the job: Live On Coliru
From http://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt (emphasis and ellipsis mine):
2) ... reads characters from is and appends them to str ... until one
of the following conditions becomes true:
...
...
std::isspace(c,is.getloc()) is true for the next character c in is (this whitespace character remains in the input stream). ...
Basicaly what this means is that if you extract a string from an istream using operator >> it stops at white spaces.
If you want to get everything from the stream into your string there are plenty of questions asking that (Like this one or this one).
Edit: Definition of class TF:
class TF {
std::vector<V4f> waypoints;
std::vector<int> densityWaypoints;
public:
std::size_t size() const { return waypoints.size(); }
friend std::ostream& operator<<(std::ostream& str, const TF& tf);
friend std::fstream& operator<<(std::fstream& str, const TF& tf);
// methods here
};
The question may steam from the fact that I don't understand streams, so that's probably a precondition.
Is it somehow possible to overload operator<<(std::ostream, T) so that when invoked in order to display the data structure on screen, it uses one overload, and when the data structure is written to a file, another one is used? Something like this probably:
std::ostream& operator<<(std::ostream& str, const TF& tf) {
for (std::size_t i = 0; i != tf.waypoints.size(); ++i) {
str << " { "
<< tf.densityWaypoints[i] << " : "
<< tf.waypoints[i][3] << " : "
<< tf.waypoints[i][0] << " , "
<< tf.waypoints[i][1] << " , "
<< tf.waypoints[i][2]
<< " } ";
}
str << "\n";
return str;
}
std::fstream& operator<<(std::fstream& str, const TF& tf) {
str << (int)tf.size();
for (std::size_t i = 0; i != tf.waypoints.size(); ++i) {
str << tf.densityWaypoints[i]
<< tf.waypoints[i][0]
<< tf.waypoints[i][1]
<< tf.waypoints[i][2]
<< tf.waypoints[i][3];
}
This doesn't compile with a strange error (I may be tired):
error: no match for ‘operator<<’ (operand types are ‘std::fstream {aka std::basic_fstream}’ and ‘int’)
The error occurs when I add the second operator<<() overload. The first one works fine. Tried both std::ofstream and std::fstream to the same result.
But I'm not sure if it's going to work either. Sure it's possible to define a function like int writeTF(std:fstream& str, const TF&tf), but that doesn't look C++ enough to me, not to mention the strange error that will potentially appear here, too.
I've seen code comparing the ostream's address to that of cout. I have mixed feelings about it, but it certainly worked:
std::ostream& operator<<(std::ostream& o, Foo const&)
{
if(&o == &std::cout) {
return o << "cout";
} else {
return o << "not_cout";
}
}
demo
Note that cout outputs to standard output, it's not the same thing as "the screen".
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm having a hard time trying to overload my << output operator for this class. The class has private members - enum class and string. The code I made compiles and runs, but the << operator is overloaded only for the enum class.
From what I understand and read about it, I need to make something like this:
friend ostream& operator<<(ostream& os, CDirectory const& dir)
but I seem to fail at implementing it and at this point I really have no ideas. I want to overload the operator for the whole class CDirectory and not only the enum class Filetype, that is one of the members. Is this even possible to do?
class CDirectory {
string m_strDirectory;
enum class Filetype {
Archive, Hidden, ReadOnly, System, FileNotSupported
};
multimap <CFile, Filetype> m_DirectoryMap;
public:
/* overloading operator<< for the enum class Filetype */
friend ostream& operator<<(ostream& os, Filetype const type)
{
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
return os;
}
/* explicit constructor - reads data from a file and inserts pairs
of types pair <CFile, enum Filetype> in a multimap */
CDirectory (const string& n) {
fp.open (n, ios::in);
string dirName, fileName, fType;
int fileSize;
Filetype filetype;
fp >> dirName;
m_strDirectory = dirName;
while (fp >> fileName >> fileSize >> fType) {
CFile obj (fileName, fileSize);
if (fType == "Archive")
filetype = Filetype::Archive;
else if (fType == "Hidden")
filetype = Filetype::Hidden;
else if (fType == "ReadOnly")
filetype = Filetype::ReadOnly;
else if (fType == "System")
filetype = Filetype::System;
else
filetype = Filetype::FileNotSupported;
m_DirectoryMap.insert(pair<CFile, Filetype>(CFile(obj.getFileName(), obj.getFileSize()), Filetype(filetype)));
}
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () {
auto p = m_DirectoryMap.begin();
cout << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
};
UPDATE:
I tried the following code, for implementing the overload operator << for my entire class, but it produces an error - error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'|on these lines (1 of them is in my constructor and 1 in my printMap function) - cout << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
I'm guessing that it has something to do with the p->second part, but I don't know what exactly is going on. Any thoughts on it?
Update: yep, the problem is when I try to print out the enum with p->second. If I remove that part it compiles..
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
const Filetype& type;
switch (type)
{
case Filetype::Archive:
os << "archive";
break;
case Filetype::Hidden:
os << "hidden";
break;
case Filetype::ReadOnly:
os << "read-only";
break;
case Filetype::System:
os << "system";
break;
case Filetype::FileNotSupported:
os << "not-supported";
break;
}
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
os << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
I assume in the end you want to be able to do something like this:
CDirectory dir("input_file");
std::cout << dir;
and this should output everything at once (basically everything that CDirectory::printMap() currently prints, right?
For this to work, you need to overload operator<< for your CDirectory class as a non-member function:
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
os << dir.m_strDirectory << "\n";
for(auto &p : dir.m_DirectoryMap) {
std::cout << p.first.getFileName() << '\t' << p.first.getFileSize() << '\t' << p.second << '\n';
}
return os;
}
and then make this function a friend of your class:
friend std::ostream& operator<<(std::ostream &os, const CDirectory &dir);
for it to be able to access the class's private members.
Alternatively, because you already have a print function in your class, you can just forward to that one so you don't need to make operator<< a friend (some people frown on friend functions). For this to work, you have to change your printMap() function a bit:
void printMap (std::ostream &os) const
{
auto p = m_DirectoryMap.begin();
os << m_strDirectory << endl;
while ( p != m_DirectoryMap.end()) {
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
std::ostream& operator<<(std::ostream &os, const CDirectory &dir)
{
dir.printMap();
return os;
}
Once you have this operator, written in either of the two variants, in your main() function you can write:
CDirectory dir("input_file");
std::cout << dir;
Two notes regarding the operator that you already overloaded for Filetype. It is the only other operator that is necessary to be overloaded for your class to be streamable (operator<< is already overloaded for std::string and integer types, so you don't have to do it to be able to write strings and numbers). Also keep in mind that, even though you wrote it inside your class, it is not actually a member function and can't be a member function (why?). You were able to define it there because you declared it friend, but the usual way of defining friend functions is this:
class A {
...
friend void f();
...
};
void f() {
...
}
I have the impression that you are confused between data members of your class and nested types (member types). Operators are (to be) defined for types, not data members.
You have to overload the operator<< (for stream output) for every class/type for which you want to use it and for which it is not already defined. From your code, I reckon that you only need to overload
ostream& operator<<(ostream& os, Filetype const type)
which you did. So it is unclear what precisely your problem is and what it symptoms are.
It seems to me you have everything you need, you just need to put it together.
printMap() function already prints everything in your class CDirectory. It prints everything to cout. So you could just do the following and it should work.
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap();
}
However this code is not well written since the opeartor<< is more general and not just made for cout. To make it better you could rewrite your printMap() function to be take a reference to ostream to which you want to output.
void printMap (ostream& os)
{
os << m_strDirectory << endl;
auto p = m_DirectoryMap.begin();
while ( p != m_DirectoryMap.end())
{
os << endl << p->first.getFileName() << '\t' << p->first.getFileSize() << '\t' << p->second << endl;
++p;
}
}
void printMap () { printMap(std::cout); }
Now the operator would look like this:
friend ostream& operator<<(ostream& os, const CDirectory& dir)
{
dir.printMap(os);
}
I hope this better explains what is going on.
I'm trying to print an object Order (actually a vector of Orders). Order has some data members, including a vector with other objects, Purchase.
I can print the vector<Purchase> to cout on its own, and I can print vector<Objects> if I ignore the vector<Purchase> member. But the tricky part is to print vector<Objects> with vector<Purchase> included.
Here is my code:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std;
struct Purchase {
string name;
double unit_price;
int count;
};
struct Order {
string name;
string adress;
double data;
vector<Purchase> vp;
};
template<typename Iter> //this is my general print-vector function
ostream& print(Iter it1, Iter it2, ostream& os, string s) {
while (it1 != it2) {
os << *it1 << s;
++it1;
}
return os << "\n";
}
ostream& operator<<(ostream& os, Purchase p) {
return os << "(" << p.name << ", " << p.unit_price << ", " << p.count << ")";
}
ostream& operator<<(ostream& os, Order o) {
vector<Purchase> vpo = o.vp;
ostringstream oss;
oss << print(vpo.begin(), vpo.end(), oss, ", "); //This is what I would like to do, but the compiler doesn't like this conversion (from ostream& to ostringstream)
os << o.name << "\n" << o.adress << "\n" << o.data << "\n"
<< oss << "\n";
return os;
}
int main() {
ifstream infile("infile.txt");
vector<Order> vo;
read_order(infile, vo); //a function that reads a txt-file into my vector vo
print(vo.begin(), vo.end(), cout, "");
return 0;
}
As you can see, I had the idea to use ostringstreams as a temporary variable, that I would store the vector<Purchase> before I pass it on to the ostream& os. But this is a no go. What would be a good solution to this problem?
I am fairly new to C++ and are just learning the different uses of streams, so please bear with me if this is a stupid question.
Looks like you have two minor typos.
First, remove the indicated portion:
oss << print(vpo.begin(), vpo.end(), oss, ", ")
// ↑↑↑↑↑↑↑
Then, later in that same function, you cannot stream a stringstream, but you can stream the string serving as its underlying buffer, so use std::stringstream::str():
os << o.name << "\n" << o.adress << "\n" << o.data << "\n"
<< oss.str() << "\n";
// ↑↑↑↑↑↑
With those fixes in place, and the missing read_order function abstracted away, your program compiles.
The easiest way is to write an overload of operator<< that takes a const reference to a std::vector<Purchase> and then just stream the vector into the ostream:
std::ostream& operator<<(std::ostream& os, const std::vector<Purchase>& v);
here is my function
ostream margain(std::string firstWord)
{
ostream x;
x << std::setw(20) << firstWord;
return x;
}
in main I want to use the function as follow
std::cout<< margain("start") << "````````````````````````````````````" << std::endl;
// print things out
//then
std::cout<< margain("End") << "````````````````````````````````````" << std::endl;
I get the output, start or end is not shown, and the return value is
0````````````````````````````````````
how can I fix it? and why?
Edit:
I know that the function is what causing that, because if I add this
cout << std::setw(20) << firstWord;
in the function, It prints right,
I fixed it, not the best way, but as
calling the function as
margain(std::cout, "End") <<
"~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~" << endl;
the function looks like
ostream& margain(ostream& stream, std::string firstWord)
{
stream << std::left << std::setw(10) << firstWord;
return stream;
}
anyone know better way?
You are printing the value of the ostream, not value of firstword. The ostream x in this case is an unopened stream, so it doesn't "do" anything. Because the compiler allows to conversion to either bool (C++11) or void * (before C++11), the "value" from that conversion is printed. Note that any operations on x will not affect cout.
The easiest solution, I would think is to actually add std::setw(20) to your output line:
std::cout<< std::setw(20 << "End" << "````````````````````````````````````" << std::endl;
The other choice would be to pass the std::cout to margain, and return the std::string, something like this:
std::string margain(ostream& x, const std::string& firstWord)
{
x << std::setw(20);
return firstWord;
}
then you could do:
std::cout<< margain(cout, "start") << "````````````````````````````````````" << std::endl;
But it's not exactly flexible or "neat".
The third option is of course to have a MarginString class:
class MarignString
{
private:
int margin;
std::string str;
public:
MarginString(int margin, std::string str) margin(margin), str(str) {}
operator std::string() { return str; }
friend std::ostream& operator(std::ostream& os, const MarginString& ms);
};
std::ostream& operator(std::ostream& os, const MarginString& ms)
{
os << std::setw(ms.margin) << ms.str;
return os;
}
...
std::cout<< MarginString(20, "start") << "````````````````````````````````````" << std::endl;
Note that this last way is probably not that great either... ;)
struct margin
{
margin(std::string word) : word(word) { }
friend std::ostream& operator <<(std::ostream& os, margin const& m)
{
return os << std::setw(20) << m.word;
}
private:
std::string word;
};