Overloading << operator to print vector<MyClass> - c++

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.

Related

using iterator in ostream fails

I am attempting to implement a std::list to replace a linked list in this assignment. I am not allowed to change the declarations and can only change code in the .cpp file. For the most part I am making progress but I am having trouble implementing this
std::ostream& operator<< (std::ostream& out, const Section& section);
namely when I try to create an iterator it fails. I've used the iterator elsewhere in the code so I don't understand why it's failing here, I believe it's because it's private but I'm not sure how to resolve the issue without changing the .h file which was explicitly prohibited:
std::ostream& operator<< (std::ostream& out, const Section& section)
{
// 1. print the section header
out << setw(8) << left << section.getCourse()
<< setw(6) << left << section.getCallNumber();
out << ": " << section.getNumberOfStudents() << " students\n";
// 2. collect the students, sort, and print
Student* students = new Student[section.getNumberOfStudents()];
{
int i = 0;
for ( auto pos = section.students.begin();
pos != section.students.end(); pos++)
{
students[i] = pos;
++i;
}
}
sort (students, students+section.getNumberOfStudents());
for (int i = 0; i < section.getNumberOfStudents(); ++i)
out << " " << students[i] << "\n";
out << flush;
return out;
}
students[i] = pos;
should be changed to
students[i] = *pos;
because you want to copy the Student the iterator references, not the iterator itself.
But why a dynamic array of Student rather than a std::vector<Student>? Currently you have a memory leak because you don't delete[] students;
Edit 1
Removed.
Edit 2
Other than that, all I can see that it wrong is a missing std:: in front of
sort (students, students+section.getNumberOfStudents());
this is assuming there is no custom sort method being used.
Edit 3
Going off the rails here:
students[i] = *pos;
copies a Student from the list into the dynamic array students. This could be expensive, so here is an alternative:
First the bits and pieces needed to prove this out: Required includes
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>
a minimal Student class
class Student
{
std::string name;
public:
Student(std::string inname):name(inname)
{
}
const std::string & getname() const
{
return name;
}
friend bool operator<(const Student & a, const Student &b)
{
return a.name < b.name;
}
};
a minimal Section class
class Section
{
public:
std::list<Student> students;
};
a minimal outstream operator
std::ostream& operator<<(std::ostream& out, const Section& section)
{
A std::vector instead of an array, and a vector of constant references so we don't have to copy the students.
std::vector<std::reference_wrapper<const Student>> students;
Store references in the vector. Probably could do a one liner with std::copy and std::back_inserter, but this is getting a bit too much to absorb for one example.
for (const auto & student: section.students)
{
students.push_back(std::ref(student));
}
Sort the vector
std::sort(students.begin(), students.end());
print the vector
for (const auto & student: students)
{
out << student.get().getname() << " ";
}
return out;
}
and one main to rule them all and in the darkness bind them
int main()
{
Section s;
s.students.emplace_front("Tom");
s.students.emplace_front("Dick");
s.students.emplace_front("Harry");
std::cout << s;
}
And all in one easy to cut-n-paste block:
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>
class Student
{
public:
std::string name; // this is me being lazy. name should be private
Student(std::string inname):name(inname)
{
}
const std::string & getname() const
{
return name;
}
friend bool operator<(const Student & a, const Student &b)
{
return a.name < b.name;
}
};
class Section
{
public:
std::list<Student> students;
};
std::ostream& operator<<(std::ostream& out, const Section& section)
{
std::vector<std::reference_wrapper<const Student>> students;
// store references in the `vector`.
for (const auto & student: section.students)
{
students.push_back(std::ref(student));
}
// Sort the `vector`
std::sort(students.begin(), students.end());
// print the `vector`
for (const auto & student: students)
{
out << student.get().getname() << " ";
}
return out;
}
int main()
{
Section s;
s.students.emplace_front("Tom");
s.students.emplace_front("Dick");
s.students.emplace_front("Harry");
std::cout << s;
}
Or do what Remy suggested and use a std::vector<Student *> and a custom comparator to dereference the pointers for std::sort.
As others have stated, the error is because you are not dereferencing the iterator when populating your students[] array:
students[i] = pos; // <-- should be *pos instead!
I would suggest an alternative approach that should be faster and more efficient:
std::ostream& operator<< (std::ostream& out, const Section& section)
{
// 1. print the section header
out << setw(8) << left << section.getCourse()
<< setw(6) << left << section.getCallNumber();
out << ": " << section.getNumberOfStudents() << " students\n";
// 2. collect the students, sort, and print
std::vector<const Student*> students;
students.reserve(section.getNumberOfStudents());
for ( auto pos = section.students.cbegin();
pos != section.students.cend(); ++pos)
{
students.push_back(&(*pos));
}
sort (students.begin(), students.end(),
[](const Student *a, const Student *b) { return (*a < *b); }
);
for ( auto pos = students.cbegin();
pos != students.cend(); ++pos)
{
out << " " << *(*pos) << "\n";
}
out << flush;
return out;
}
I appreciate all your answers. Ended up being a much more basic issue. I had to implement the Section iterators to return student iterators.
Section::iterator Section::begin() {
return students.begin();
}
Section::const_iterator Section::begin() const {
return students.begin();
}
Section::iterator Section::end() {
return students.begin();
}
Section::const_iterator Section::end() const {
return students.begin();
}

print vector of objects within an object

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);

Outputing a list separated by space

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 [ ].

Error : No operator “<<” matches these operands

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

issue with ostream and << overloading

I have this printing line of code:
std::cout << *it << std::endl;
now, since 'it' is a complex type I need to write my own '<<' operator.
this is my function:
friend ostream& operator<<(ostream& os, const Node& n ){
return os << n.key << ':' << n.value;
}
I get an error "type ostream could not be resolved"
I've tried adding std:: before "ostream" but that doesn't help. I'm not sure what else I can try.
You need to #include <ostream> (<iostream> is not be enough if you're using C++03).
If you've done that, and used the std:: qualifying prefix, then there's something you're not telling us or you're compiling the wrong file!
#include <ostream> // for std::ostream
#include <iostream> // for std::cout
struct Node
{
int key;
int value;
};
std::ostream& operator<<(std::ostream& os, const Node& n) {
return os << n.key << ':' << n.value;
}
int main()
{
Node n = {3, 5};
std::cout << n << '\n';
}
// Output: `3:5`
Live demo