I'm overloading operator << to output my container separated by space:
std::ostream& operator<< (std::ostream &os, const MyContainer &v)
{
os << "[";
for (const auto &i : v) {
os << i << " ";
}
os << "\b]"; // <--
return os;
}
MyContainer c{1,2,3};
std::cout<<c<<std::endl;
I'm using '\b' to avoid the extra space at the end of the list, it works fine with above code.
But it might not be a good idea, does '\b' work well with other types of ostream? Any other idea to output data like this?
But it might not be a good idea, does '\b' work well with other types of ostream?
You are absolutely right about this not being a good idea: '\b' works fine in console mode, but it does not play well with other streams, such as files.
A better approach is to not output the extra space in the first place:
std::ostream& operator<< (std::ostream &os, const MyContainer &v)
{
os << "[";
auto first = true;
for (const auto &i : v) {
if (!first) {
os << " ";
} else {
first = false;
}
os << i;
}
os << "]";
return os;
}
A simple pragmatic solution is to just add a space before the range loop:
std::ostream& operator<< (std::ostream &os, const MyContainer &v)
{
os << "[ "; // <--
for (const auto &i : v) {
os << i << " ";
}
os << "]";
return os;
}
MyContainer c{1,2,3};
std::cout<<c<<std::endl;
The result is a slightly different output, but still achieves the presumed goal of visually pleasing symmetrical formatting: instead of [1 2 3] you get [ 1 2 3 ]. Empty lists will print as [ ].
Related
I'm trying to overload the << operator to print a vector that contains elements of type Position (vector).
I managed to overload the << operator for type Position, but I can't figure out how to do it for vector. Can you help?
//position.h
#ifndef POSITION_H
#define POSITION_H
#include <iostream> // using IO functions
using namespace std;
class Position {
private:
int row;
int column;
public:
friend ostream& operator<<(ostream& os, const Position& P);
friend ostream& operator<<(ostream& os, const vector<Position>& VP);
};
#endif
//position.cpp
#include"Position.h"
#include <iostream> // using IO functions
#include<vector>
ostream& operator<<(ostream& os, const Position& P)
{
os << '(' << P.row << ',' << P.column << ')' << endl;
return os;
}
ostream& operator<<(ostream& os, const vector<Position>& VP)
{
Position placeholder;
for (int i = 0; i != VP.size(); i++)
{
placeholder = VP.at(i);
cout << placeholder << endl;
}
return os;
}
int main()
{
Position C1(2, 1);
Position C2(3, 1);
Position C3(4, 1);
vector<Position> cans;
cans.push_back(C1);
cans.push_back(C2);
cans.push_back(C3);
cout << cans;
system("pause");
}
I'm sure there's a duplicate on StackOverflow somewhere, but I cannot find it. I'm a bit surprised about this question, as I don't really see a critical issue at first sight. Did you get a compiler error or segmentation fault?
Every time you assign to Placeholder, you make a copy. This is not necessary at all: you can directly access the element at the index. As you limit the index to 0 to size(), you don't have to worry about going out-of-bounds, so don't use .at(i), which throws an exception if you go out of bounds. Just use VP[i].
Also not that std::endl flushes the buffer, which is slow. A normal enter/end-line can be achieved with the '\n' character.
Finally, using namespace std; is considered bad practice.
You have multiple options for processing the elements of the vector:
index-based for loop:
for (int i = 0; i != VP.size(); ++i) {
os << VP[i] << '\n';
}
Iterator-based for loop
for (auto it = cbegin(VP); it != cend(VP); ++it) {
os << *it << '\n';
}
range-based for loop
for (auto const& el : VP) {
os << el << '\n';
}
Algorithm for(each) loop
std::for_each(cbegin(VP), cend(VP),
[](auto const& el) { os << el << '\n'; });
Copy to ostream_iterator
std::copy(cbegin(VP), cend(VP),
std::ostream_iterator<Position>(os, "\n"));
Note that here you could also write <decltype(VP)::value> instead of <Position> to keep it generic, but that might be overkill in this situation.
And the last two have a C++20 ranges equivalent:
std::ranges::for_each(VP,
[](auto const& el) { os << el << '\n'; });
std::ranges::copy(VP,
std::ostream_iterator<Position>(os, "\n"));
Note:
friend ostream& operator<<(ostream& os, const vector<Position>& VP); doesn't have to be a friend of Position! It doesn't require access to the private members.
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 still fairly rusty at c++ and I'm having trouble understanding my issue. The error message that I am receiving is "No operator '<<' matches these operands" The code I have:
for(int i = 0; i < ruleList.size(); i++)
{
cout << ruleList[i].lhs << endl;
cout << ruleList[i].rhs << endl; // Problem printing this
}
struct Rules
{
string lhs;
vector<string> rhs;
}rule;
vector<Rules> ruleList;
Would this be the appropriate way to do this? I did the lhs the same way and it works fine.
rule.rhs.push_back(token);
ruleList.push_back(rule);
There is no operator<< defined for standard containers. You will need to write a print function, something along the lines of:
void print(std::ostream& out, std::vector<std::string> const & data) {
std::copy(data.begin(), data.end(),
std::ostream_iterator<std::string>(out, " "));
}
And then use it as:
print(std::cout, ruleList[i].rhs);
std::vector does not define an operator <<. You can use a std::ostream_iterator to format a list:
std::copy( ruleList[i].rhs.begin(), ruleList[i].rhs.end(),
std::ostream_iterator< std::string >( std::cout, ", " ) );
This is a bit imperfect in that ", " is printed after the final element, but that can be worked around.
You need to write your own << operator for struct rules. It should look something like this in C++11:
struct rules {
string lhs;
std::vector<std::string> rhs;
// apparently it's a good idea to keep this out of std:: namespace
inline static std::ostream & operator << (std::ostream & out, const rules & r) {
out << r.lhs << std::endl;
//for (int i = 0; i < v.length(); i++)
for (auto & s : r.rhs) {
out << s;
}
out << std::endl;
return out;
}
}
MSDN has a write up here: http://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx
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;
};
I have a program that should emulate a simple filesystem, I want to print the structure of directories, so I have overloaded the << operator, and called another function that goes through my structure in rectursion. It works, BUT there are some weird hex values before some of the lines in the output. Is there something wrong with the way I manipulate iwth the ostream ? (I did not include the class definition, but it shouldnt matter)
Thanks all, for any answers!
std::ostream& printTree(std::ostream& os, const CFileSystem::TDir* x, int nmbTabs)
{
int k;
const CFileSystem::TDir * nxt = x;
//cout << pocetTabu<<endl;
while(nxt){
os<<"--";
for(k=0;k<nmbTabs;k++){
os << '\t' ;
}
os<<"--";
os << nxt->m_Name << endl;
if(nxt->m_Sub){
os << printTree(os,nxt->m_Sub,nmbTabs+1);
}
nxt=nxt->m_Next;
}
return os;
}
std::ostream& operator <<(std::ostream& os, const CFileSystem& x)
{
os << "/" << endl;
os << printTree(os, x.m_Root,1);
return ( os );
}
os << printTree(os, x.m_Root,1);
What is this? printTree returns std::ostream &, and you're trying to output that (an ostream)?
That should be this:
printTree(os, x.m_Root,1);
That means, your operator<< should be implemented as:
std::ostream& operator<<( std::ostream & os, const CFileSystem & x)
{
os << "/" << std::endl;
return printTree(os, x.m_Root,1);
}