How to add an operator<< for templated class? - c++

I need to add operator<< to make my cout working.
Code template.cpp:
#include "maptemplate.h"
int main(void)
{
typedef unsigned int ID; //Identification number of Employee
map_template<ID,Employee> Database; //Database of employees
Database.Add(761028073,Employee("Jan Kowalski","salesman",28)); //Add first employee: name: Jan Kowalski, position: salseman, age: 28,
Database.Add(510212881,Employee("Adam Nowak","storekeeper",54)); //Add second employee: name: Adam Nowak, position: storekeeper, age: 54
Database.Add(730505129,Employee("Anna Zaradna","secretary",32)); //Add third employee: name: Anna Zaradna, position: secretary, age: 32
//cout << Database << endl; //Print databese
//map_template<ID,Employee> NewDatabase = Database; //Make a copy of database
Employee* pE;
pE = Database.Find(510212881); //Find employee using its ID
pE->Position = "salesman"; //Modify the position of employee
pE = Database.Find(761028073); //Find employee using its ID
pE->Age = 29; //Modify the age of employee
//Database = NewDatabase; //Update original database
///cout << Database << endl; //Print original database
cout<<"Wszystko dziala"<<endl;
}
Code: template.h
#include <iostream>
#include <vector>
using namespace std;
// Początek klasy Employee bez template
class Employee
{
private:
public:
Employee(string Name, string Position, int Age);
string Name;
int Age;
string Position;
}; // koniec klasy employee
// Dodanie pól Name, Age, Position
Employee::Employee(string Name, string Position, int Age)
{
this->Name = Name;
this->Age = Age;
this->Position = Position;
}
template <class Key, class T> // template <klucze, dane pracownikow>
class map_template
{
private:
vector<Key> keys; // vector do przechowywania unikalnych kluczy pracowników
vector<T> content; // vector do przechowywania danych pracowników
public:
map_template()
{
}
void Add(Key key, T t);
T* Find(Key key);
}; // koniec klasy map_template
// Dodanie do bazy (Add)
template <class Key, class T>
void map_template<Key, T>::Add(Key key, T t)
{
keys.push_back(key);
content.push_back(t);
}
// Szukanie w bazie (Find)
template <class Key, class T>
T* map_template<Key, T>::Find(Key key)
{
for (unsigned int i = 0; i < keys.size(); i++)
if (keys[i] == key)
{
return &content.at(i);
}
return nullptr;
}
I was thinking how i should look at it. Its my first time using templates so i dont know how operator<< should look like.
Was thinking about something like:
friend ostream & operator<< (ostream & s, teamplate<something>);
But dont really know how to add it.
I need
cout << Database << endl;
to work properly.
Sorry for some polish language comments.
Edit:
I tried putting this friend declaration in the class Employee but i keep getting errors :(
code:
class Employee
{
private:
public:
Employee(string Name, string Position, int Age);
string Name;
int Age;
string Position;
friend ostream &operator << (ostream &out, const map_template<Key, T> &map);
}
errors:
maptemplate.h:49:63: error: ‘Key’ was not declared in this scope
friend ostream &operator << (ostream &out, const map_template<Key, T> &map);
^~~
maptemplate.h:49:68: error: ‘T’ was not declared in this scope
friend ostream &operator << (ostream &out, const map_template<Key, T> &map);
^
maptemplate.h:49:69: error: template argument 1 is invalid
friend ostream &operator << (ostream &out, const map_template<Key, T> &map);
^
maptemplate.h:49:69: error: template argument 2 is invalid
maptemplate.h: In instantiation of ‘std::ostream& operator<<(std::ostream&, const
map_template<Key, T>&):
Should i change the declaration or what? I know that Key and T are in private. Maybe thats the case?
Anyone can help?
I'm a begginer so :/

You want:
template <class Key, class T>
std::ostream& operator << (std::ostream& out, const map_template<Key, T>& map) {
// your logic on how to output the map here...
return out;
}
so your operator<< will work with map_template of any specialization.
Obviously, your friend approach would also be suitable, plus you would actually drop the unnecessary template line. If you place your operator << declaration inside your class, this:
friend std::ostream& operator << (std::ostream& out, const map_template<Key, T>& map) {
// your logic on how to output the map here..
return out;
}
will do just fine. Notice the lack of repeated template <class Key, class T>. Inside your class - those template types are visible and thus you can use them.

Related

Overloading ">>" for a template?

I'm trying to overload the ">>" operator so i can read and store a new Atlas<Animal *> from the keyboard.
The atlas template class has a list in which i'm storing pointers to each Animal object. Here is the code:
class Animal {
protected:
std::string m_name;
public:
Animal() {}
Animal (std::string name): m_name {name} {}
virtual void set_name(std::string name) {m_name = name;}
virtual std::string get_name () {return m_name;}
virtual std::string regn() const { return "???"; }
virtual ~Animal(){
cout << "Destructor animal"<<'\n';}
friend istream& operator >> (istream &in, Animal* k){
in>> k->m_name;
return in;}
}; //pointers to objects from this class will be stored in Atlas2;
//declaration for >> operator
template <class T>
class Atlas2;
template<typename T>
std::istream& operator>>(std::istream& in, const Atlas2<T>& A);
// Template class
template<class T>
class Atlas2{
public:
int nr_pesti;
int m_length;
std::list<T> pages;
Atlas2(){m_length = 0; nr_pesti = 0;}
~Atlas2(){}
void adauga(T data);
Atlas2 operator += (const T& data){
this->m_length++;
this->pages.push_back(data);
return *this;}
friend std::istream& operator>> <> (std::istream& in, const Atlas2<T>& A);
};
template <class T>
istream operator>> (istream &in, const Atlas2<T> &A)
{
in >> A.m_length;
for (int i=1; i<=A.m_length; i++){
T data = new T;
cin >> data;
A.pages.push_back(data);}
return in;
}
template <class T>
void Atlas2<T>::adauga(T data){m_length = m_length+1;
pages.push_back(data);}
// here's the main:
int main(){
Atlas2<Animal *> Atlas3;
cin >> Atlas3;
return 0;}
What am I doing wrong here? I get this error when compiling:
ambiguous overload for 'operator>>' (operand types are 'std::istream' {aka 'std::basic_istream<char>'} and 'Atlas2<Animal*>') at line 58 (Where i type cin>>Atlas3) and these Warnings for the >> operator in the template class : note: candidate: 'std::istream& operator>>(std::istream&, const Atlas2<T>&) [with T = Animal*; std::istream = std::basic_istream<char>]'

C++ Trying to add >> Operator Overload To Template

I have a class IPrintable which is a template and a class which derives from it - Date. I want to add the operator >> to the template but keep getting an error:
source.cpp(16): error C2259: 'Date': cannot instantiate abstract class
source.cpp(16): note: due to following members:
source.cpp(16): note: 'void IPrintable<Date>::toIs(std::istream &)': is abstract
iprintable.h(19): note: see declaration of 'IPrintable<Date>::toIs'
I have successfully added the << operator to the template this way:
virtual void toOs(ostream& os) const = 0;
friend ostream& operator << (ostream& output, const IPrintable& toPrint) {
toPrint.toOs(output);
return output;
}
And then I have declared virtual void toOs(ostream& os) const = 0; to date.h and implemented it in date.cpp.
This is my IPrintable.h:
#pragma once
#include <iostream>
#include <string>
using namespace std;
template <class T>
class IPrintable {
private:
public:
virtual void toOs(ostream& os) const = 0;
friend ostream& operator << (ostream& output, const IPrintable& toPrint) {
toPrint.toOs(output);
return output;
}
virtual void toIs(istream& input) = 0;
friend istream& operator >> (istream& input, IPrintable& toSet) {
toSet.toIs(input);
return input;
}
};
This is the declaration of in Date.h, under public:
virtual void toOs(ostream& output) const;
virtual void toIS(istream& input);
This is the implementation of the << (toOs) and >> (toIs) in Date.cpp:
void Date::toOs(ostream& output) const {
if (!isLeapYear(this->getDay(), this->getMonth(), this->getYear())) {
cout << "Not a leap year";
return;
}
output << getDay() << "/" << getMonth() << "/" << getYear();
}
void Date::toIS(istream& input) {
int index;
string str;
input >> str;
index = str.find('/');
this->setDay(stoi(str.substr(0, index)));
str = str.substr(index + 1);
index = str.find('/');
this->setMonth(stoi(str.substr(0, index)));
str = str.substr(index + 1);
this->setYear(stoi(str));
}
Please, if any more information is needed please let me know and I will do my best to provide it.
Thanks!
Your Date::toIS has a capital S, while your IPrintable::toIs does not. If you add override to the declaration of Date::toIS, you would see that it doesn't actually override anything.

How can I read data from file to vector?

So I have this code where an object of class Group has vector with objects from class Student. I am already writing information about the students from the vector into a file but I have problem with reading this information back. How can I do that?
Here is my code so far:
class Group
{
private:
string name;
vector <Student*> studentList;
public:
~Group();
Group(void);
Group(string s);
void addStudent(string name,int age,int stNum);
void removeStudent(int stNum);
friend ostream& operator << (std::ostream& out, const Group& g) {
out << g.name << "\n";
out << g.studentList.size() << "\n";
for (unsigned i=0;i<g.studentList.size();i++) {
out<< g.studentList[i]->getStudentName()<<"\n";
out<< g.studentList[i]->getStudentAge()<<"\n";
out<< g.studentList[i]->getStudentNumber()<<"\n"<<endl;
}
return out;
}
friend istream& operator>>(std::istream& in, Group& g){
in >> g.name;
for (unsigned i=0;i<g.studentList.size();i++) {
//READ DATA FROM FILE
}
return in;
}
};
Gathering up the commentary. Note this pushes the hard part, the reading and writing, into Student and I left that bit blank. Normally I'd do it because I'm evil, but apparently in this case it is already written.
Major changes:
No Student pointers. Lest memory management overhead and better cache friendliness! By Grabthar's hammer. What a savings.
Student does the Student reading and writing.
std::vector handles the element counting so it doesn't need to be stored in and read from the output. Note: This could slow the reading down a little because you can't pre-allocate storage in the vector.
#include <string>
#include <iostream>
#include <vector>
// note the lack of using namespace std;
// it can be problematic, and especially so in a header.
class Student
{
//fill in the blanks
friend std::ostream& operator <<(std::ostream& out, const Student& s)
{
//fill in the blanks
return out;
}
friend std::istream& operator >>(std::istream& in, const Student& s)
{
//fill in the blanks
return in;
}
};
class Group
{
private:
std::string name;
std::vector<Student> studentList; // death to pointers!
public:
//~Group(); // Don't need a destructor without the pointer
Group(void);
Group(std::string s);
void addStudent(std::string name, int age, int stNum);
void removeStudent(int stNum);
friend std::ostream& operator <<(std::ostream& out, const Group& g)
{
out << g.name << "\n";
//out << g.studentList.size() << "\n"; not necessary. vector handles it.
for (std::vector<Student>::const_iterator it = g.studentList.cbegin();
it != g.studentList.cend();
++it)
{
if (!(out << *it))// let Student's << do all the work
{ // write failed. Might as well stop trying to write.
break;
}
}
return out;
}
friend std::istream& operator>>(std::istream& in, Group& g)
{
in >> g.name;
Student temp;
while (in >> temp) // let Student's >> do all the work
{
g.studentList.push_back(temp);
}
return in;
}
};

Overloading extraction operator for a custom class set

I've made a custom class user, and made a set<user> users in another class dbase. I've successfully overloaded the extraction operator for the class user and now I'm trying to overload the extraction operator for the class dbase.
This is my code:
ostream& operator<< (ostream &out, dbase &db) {
set<user>::iterator it;
for(it=db.users.begin(); it!=db.users.end(); it++)
out<<(*it)<<endl; //error reported on this line
return out;
}
But I keep on getting this error:
error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
This is the operator<< declaration of class user:
ostream& operator<<(ostream &out, user &u) {
cout<<endl;
cout<<"Username: "<<u.uname;
cout<<endl;
return out;
}
Here is the complete code: (ideone)
#include <iostream>
#include <set>
#include <string>
#include <sstream>
using namespace std;
template <class T>
string to_string(T x) {
stringstream ss;
ss<<x;
return ss.str();
}
class date {
int dd,mm,yyyy;
string str_date;
public:
string get_date() {
return to_string(dd)+"-"+to_string(mm)+"-"+to_string(yyyy);
}
friend ostream& operator << (ostream&,date&);
friend istream& operator >> (istream&,date&);
};
ostream& operator<< (ostream &out, date &d) {
out<<d.get_date();
return out;
}
istream& operator>> (istream &in, date &d) {
cin>>d.dd>>d.mm>>d.yyyy;
return in;
}
class user {
string uname, pwd;
string full_name, contact;
static unsigned long long int id;
date dob;
public:
bool operator < (const user &u) const {
if(uname.compare(u.uname)<0) return true;
return false;
}
void set_uname(string u) {
uname = u;
}
void set_attrib() {
string temp_pass;
while(1) {
cout<<"Full Name: ";
cin>>full_name;
cout<<"Password: ";
cin>>temp_pass;
cout<<"Confirm Password: ";
cin>>pwd;
if(pwd.compare(temp_pass))
cout<<"Passwords do not match. Try Again."<<endl;
else break;
}
cout<<"Contact Number: ";
cin>>contact;
cout<<"Date of Birth(dd mm yyyy): ";
cin>>dob;
}
friend ostream& operator<<(ostream&, user&);
};
ostream& operator<<(ostream &out, user &u) {
cout<<endl;
cout<<"Username: "<<u.uname;
cout<<endl;
return out;
}
class dbase {
set<user> users;
public:
void add_user() {
string uname;
user u;
while(1) {
cout<<"Username: ";
cin>>uname;
u.set_uname(uname);
if(users.find(u)==users.end()) {
u.set_uname(uname);
u.set_attrib();
users.insert(u);
break;
}
else
cout<<"Username already exists. Please try a different username."<<endl;
}
}
friend ostream& operator << (ostream&, dbase&);
};
ostream& operator<< (ostream &out, dbase &db) {
set<user>::iterator it;
user u;
for(it=db.users.begin(); it!=db.users.end(); it++)
out<<(*it)<<endl;
return out;
}
int main() {
return 0;
}
So...
Lesson 1
Please post a complete compilable example. In this case, you didn't provide enough information for us to easily debug your code.
For your particular problem, that code would probably look something like this:
#include <iostream>
#include <set>
using namespace std;
class user {
public:
user(int id = 0): id(id) {}
int id;
};
class dbase {
public:
set<user> users;
};
bool operator<(user const & lhs, user const & rhs) {
return lhs.id < rhs.id;
}
ostream& operator<< (ostream &out, user & user) {
return out << "user(" << user.id << ")";
}
ostream& operator<< (ostream &out, dbase &db) {
set<user>::iterator it;
user u;
for(it=db.users.begin(); it!=db.users.end(); it++)
cout<<*it<<endl;
return out;
}
int main() {
dbase db;
db.users.emplace(3);
db.users.emplace(4);
cout << db << endl;
}
Lesson 2
Please post the entire error message that your compiler reports. In this case, it would actually be:
se.cc: In function ‘std::ostream& operator<<(std::ostream&, dbase&)’:
se.cc:28:16: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
cout<<*it<<endl;
^
In file included from /opt/gcc/4.8.1/include/c++/4.8.1/iostream:39:0,
from se.cc:1:
/opt/gcc/4.8.1/include/c++/4.8.1/ostream:602:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = user]’
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
Note that I haven't edited the error message in any way. It's possible that there is additional information in the message that you're missing that could be helpful to people trying to answer your question.
Lesson 3
Instead of:
ostream& operator<< (ostream &out, user & user) { ... }
Do:
ostream& operator<< (ostream &out, user const & user) { ... }
Lesson 4
When overloading the stream exaction or stream insertion operators, you should probably never use cout or cerr. Instead, you've passed a stream object into your function. In your case, you've named it with the typical (expected) argument name of out.
So, your two stream insertion operators should have every instance of cout replaced with out.
This will cause your code to work correctly when you extend it to use things like writing the user database to a file using a fstream, or if you wanted to print a message to cerr as well.
Lesson 5
Just to note. This is an issue because *it returns a reference to a const User. So your existing operator<< overload doesn't match, because it wants a non-const version of a User.

output operator overloading for queue class C++

I am trying to overload the << operator in order to print objects of classes, I tried making a friend function of the operator and then declaring it in below the Queue class, I have not written anything inside the code block here is what I have, it wont compile, it will crash instantly, thanks in advance.
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class Employee{
protected:
long empId;
string empName;
string email;
public:
Employee(){}
Employee(long i, string n){
empName = n,
empId =i;
email = "Unknown";
}
};
class Student{
protected:
long stId;
int year;
string email;
string schoolName;
public:
Student(){}
Student(long i, int y, string sn){
stId = i;
year =y;
email = "Unknown";
schoolName=sn;
}
};
template<class T>
class Queue{
protected:
vector<T> theQ;
public:
void Push(T item);
T pop();
void ReadAnItem();
void PrintQ();
**template<T>** edit
friend ostream& operator<< (ostream& is, const Queue<T>& theQ);
};
template<class T>
ostream& operator<< (ostream& os, const Queue<T>& theQ){
**os << theQ.Print();** Edit
return os;
}
template<class T>
void Queue<T>::ReadAnItem(){
T item;
cout << "Enter the data please: " << endl;
cin >> item;
Push(item);
}
template<class T>
void Queue<T>::Push(T item){
theQ.front() = item;
}
template<class T>
void Queue<T>::PrintQ(){
cout << "The content of the array is as follows: " << endl;
for (int i=0; i< theQ.size(); i++){
cout << theQ[i] << **endl;** I get an "invalid overload of endl"
}
}
You should declare that friend function as a template:
template <class U>
friend ostream& operator<< (ostream& is, const Queue<U>& theQ);
Your operator<< function is a template function, so note that inside friend declaration:
friend ostream& operator<< <T>(ostream& is, const Queue<T>& theQ);
This is not the as Andy's variant, as Andy's variant allows this:
#include <iostream>
template <class T>
class A
{
public:
A(T d): data(d){}
private:
// friend is any template instance of function foo, and not just foo<T>!
template <class U>
friend void foo(A<U>& t);
T data;
};
A<int> ai(1);
template <class T>
void foo(A<T>& t)
{
// A<int> will accept foo<double> as friend
std::cout << ai.data << std::endl;
std::cout << t.data << std::endl;
}
int main()
{
A<double> ad(2);
foo(ad);
return 0;
}
However, in my case, you need to add few forward declarations, in order to make this right:
#include <iostream>
// 2. But before that you need to forward-declare your class, so the function
// can know about the class.
template <class T>
class A;
// 1. You need to forward-declare your foo function...
template <class T>
void foo(A<T>& t);
template <class T>
class A
{
public:
A(T d): data(d){}
private:
friend void foo<T>(A<T>& t);
T data;
};
A<int> ai(1);
template <class T>
void foo(A<T>& t)
{
// error: ‘int A<int>::data’ is private within this context
//std::cout << ai.data << std::endl;
std::cout << t.data << std::endl;
}
int main()
{
A<double> ad(2);
foo(ad);
}
Here's your code, but you need more work to do:
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class Employee{
protected:
long empId;
string empName;
string email;
public:
Employee(){}
Employee(long i, string n){
empName = n,
empId =i;
email = "Unknown";
}
};
class Student{
protected:
long stId;
int year;
string email;
string schoolName;
public:
Student(){}
Student(long i, int y, string sn){
stId = i;
year =y;
email = "Unknown";
schoolName=sn;
}
};
template<class T>
class Queue;
template<class T>
ostream& operator<< (ostream& os, const Queue<T>& theQ);
template<class T>
class Queue{
protected:
vector<T> theQ;
public:
void Push(T item);
T pop();
void ReadAnItem();
void PrintQ() const;
friend ostream& operator<< <T> (ostream& is, const Queue<T>& theQ);
};
template<class T>
ostream& operator<< (ostream& os, const Queue<T>& theQ){
// I will just use this, but it should receive ostream
theQ.PrintQ();
return os;
}
template<class T>
void Queue<T>::ReadAnItem(){
T item;
cout << "Enter the data please: " << endl;
cin >> item;
Push(item);
}
template<class T>
void Queue<T>::Push(T item){
// this aint gonna work! Use std::deque and push_front! theQ.front() = item;
}
template<class T>
void Queue<T>::PrintQ() const{
cout << "The content of the array is as follows: " << endl;
for (int i=0; i< theQ.size(); i++){
// You need to overlload operator<< for student to make this work! cout << theQ[i] << endl;
}
}
int main()
{
Queue<Student> s;
s.Push(Student());
std::cout << s;
return 0;
}
Note - this code is not perfect (nor good), it just shows you how to solve this particular problem. You need to move body of PrintQ() method to operator<< or to make your PrintQ to accept and return ostream&. Also, I've already marked it as a const, as it doesn't change state of the class. Also, you don't have operator<< for student, so you are not able to output it into the ostream&. Also, vector.first() = s will always wipe your first element (it will copy s into the first element of the vector using operator=), or it will fail, if there's no first element. I'm sure there's other bugs, but these are only that I saw while trying your program.
Edit
For each different class, you need to have different operator<<. So, change the Student to:
class Student{
protected:
long stId;
int year;
string email;
string schoolName;
friend ostream& operator<<(ostream& os, const Student& s);
public:
Student(){}
Student(long i, int y, string sn){
stId = i;
year =y;
email = "Unknown";
schoolName=sn;
}
};
and add another operator<< body:
ostream& operator<<(ostream& os, const Student& s)
{
os << s.stId << s.year << s.email << std::endl;
return os;
}
Also, do this for Employee. And you should consider moving common fields from Student and Employee to base class Person.