This question already has answers here:
How can I use cout << myclass
(5 answers)
Closed 4 months ago.
I've been reading questions here for an hour or two regarding this error I'm getting and most of them forgot to #include string (which I had already done), or to overload the << operator.
Here's the code in question:
void Student::getCoursesEnrolled(const vector<Course>& c)
{
for (int i = 0; i < c.size(); i++)
{
cout << c[i] << endl;
}
}
And the error I'm getting:
Error: No operator matches these operands
operand types are: std::ostream << const Course
All I'm trying to do is return the vector. I read about overloading the << operator but we haven't learned any of that in class so I'm assuming there is another way of doing it?
I appreciate your time!
All I'm trying to do is return the vector.
Not quite; you're trying to print it using cout. And cout has no idea how to print a Course object, unless you provide an overloaded operator<< to tell it how to do so:
std::ostream& operator<<(std::ostream& out, const Course& course)
{
out << course.getName(); // for example
return out;
}
See the operator overloading bible here on StackOverflow for more information.
The problem is that operator << is not overload for type Course objects of which you are trying to output in statement
cout << c[i] << endl;
You need to overload this operator or write your own function that will output an object of type Course in std::ostream
For example let assume that below is a definition of class Course
class Course
{
private:
std::string name;
unsigned int duration;
public:
Course() : duration( 0 ) {}
Course( const std::string &s, unsigned int n ) : name( s ), duration( n ) {}
std::ostream & out( std::ostream &os ) const
{
return ( os << "Course name = " << name << ", course duration = " << duration );
}
};
When you can write
std::vector<Course> v = { { "A", 1 }, { "B", 2 }, { "C", 3 } };
for ( const Course &c : v ) c.out( std::cout ) << std::endl;
Instead member function out you can overload operator <<. For example
class Course
{
private:
std::string name;
unsigned int duration;
public:
Course() : duration( 0 ) {}
Course( const std::string &s, unsigned int n ) : name( s ), duration( n ) {}
friend std::ostream & operator <<( std::ostream &os, const Course & c )
{
return ( os << "Course name = " << c.name << ", course duration = " << c.duration );
}
};
and use it as
std::vector<Course> v = { { "A", 1 }, { "B", 2 }, { "C", 3 } };
for ( const Course &c : v ) std::cout << c << std::endl;
The stream operator << is used to "output" some representation of that object. If you don't want to overload the operator yet just pick some property to output instead:
for (int i = 0; i < c.size(); i++)
{
cout << c[i].Name << endl; // assuming Name is a property of Course
}
When you DO overload the operator you just decide then what the proper representation of a Course is:
ostream& operator<< (ostream &out, Course &c)
{
out << c.Name "(" << c.Description << ")";
return out;
}
Your Course class needs to implement an operator:
class Course
{
public:
/*
* Your code here
*/
// Probably missing this:
friend std::ostream& operator << (std::ostream& os, const Course& course)
{
os << course.name(); // etc..
return os;
};
}; // eo class Course
Since you haven't yet learned to overload operator<<, what you can do instead is to print each member of your Course class. You haven't posted the definition of Course, but perhaps it's something like this:
class Course
{
public:
int get_number() { return _number; }
const std::string& get_name() { return _name; }
private:
int _number;
std::string _name;
};
then you can say:
void Student::getCoursesEnrolled(const vector<Course>& c)
{
for (int i = 0; i < c.size(); i++)
{
cout << c[i].get_number() << " "
<< c[i].get_name() << std::endl;
}
}
Your problem is this particular part:
cout << c[i]
In your case c[i] is an object of type Course as dvnrrs correctly pointed out. So either:
implement the overloaded << operator for your object OR
if your Course object is in someway a typedef to a primitive try explicitly casting it to a string type (or similar)
Related
Here is part of my class assign_obj, constructor and operator that I want to print the object.
When trying to compile operator I am getting error :
error: 'A' was not declared in this scope for(assign_obj::item anItem : obj.*A){
Why is that?
If I try obj.A instead, I get error for the forloop as C++ can not loop a pointer of dynamic array.
class assign_obj{
private:
struct item{
char value;
int count;
};
item * A; //pointer A pointing to something of type Item
int size;
public:
assign_obj();
assign_obj(std::string);
friend std::ostream& operator<<(std::ostream & out, assign_obj & obj);
//Constructor
assign_obj::assign_obj(string aString){
size = aString.size();
A = new item[size];
item myItem;
for(int i = 0; i < size; i++){
myItem = {(char)toupper(aString[i]), 1};
A[i] = myItem;
}
}
// Print operator
std::ostream& operator<<(std::ostream & out, assign_obj & obj){
out <<"[ ";
for(assign_obj::item anItem : obj.*A){
out << anItem.value;
out << ":";
out << anItem.count;
out << " ";
}
out <<"]";
return out;
}
You can't use a for loop that way for a dynamically allocated array. You can use a plain old for loop for your plain old array.
std::ostream& operator<<(std::ostream & out, assign_obj & obj){
out <<"[ ";
for (size_t i = 0; i < obj.size; i++) {
out << obj.A[i].value << ":"
<< obj.A[i].count << " ";
}
out <<"]";
return out;
}
In c++ it is usually recomended to use std::vector, instead of raw c arrays.
You need to add:
#include <vector>
Then your member will be:
std::vector<item> A;
Allocating the items in assign_obj::assign_obj is done like this:
A.resize(size);
Finally your operator<< will be:
std::ostream& operator<<(std::ostream & out, assign_obj & obj){
out <<"[ ";
//-----------------------vvvvvvv----------vvvvv--
for(assign_obj::item const & anItem : obj.A){
out << anItem.value;
out << ":";
out << anItem.count;
out << " ";
}
out <<"]";
return out;
}
Notes:
Accessing the A member of obj is done with obj.A, not obj.*A.
Travresing the vector is done with a const& to avoid copy.
Sorry if this question has been asked before, but I'm struggling with overloading the << operator to stream different data into multiple files.
I have a Player class, which has the following attributes:
char* name;
char* password;
int hScore;
int totalGames;
int totalScore;
int avgScore;
I want to overload the << operator twice: one to stream the name, password and hScore to a "Players.txt" file, and a second overload to stream the totalGames, totalScore and avgScore to a different .txt file which is based off each player's name, e.g. "Player1.txt".
Here's what my operator looks like in the Player class:
friend ostream& operator<< (std::ostream& os, Player& player)
{
os << player.name << "\n" << player.encryptPassword((player.password), 3) << "\n" << player.hScore << "\n";
return os;
}
And here's where I am calling it, from a PlayerLibrary class which contains a vector of Players:
ofstream out("Yahtzee.txt");
if (out.is_open())
{
for_each(playerList.begin(), playerList.end(), [&out](Player* player) {out << (*player);});
}
else
{
cout << "THERE WAS AN ERROR WRITING TO FILE\n";
}
Basically, I want to stream the other variables into another file which is named after the player name, and contains a scorecard for each game they've played. So far it looks like:
for (auto it = playerList.begin(); it != playerList.end(); ++it)
{
auto position = it - playerList.begin();
string filename(playerList[position]->getName());
filename = filename + ".txt";
ofstream out2(filename);
for (int i = 0; i < playerList[position]->getNumberOfScorecards(); i++)
{
out2 << *playerList[position]->getScorecard(i);
}
}
This only streams the scorecard and not the totalGames, totalScore and avgScore, like I want it to.
I have tried just moving those variables into the scorecard class, but I feel that it makes more sense to have them where they are.
I understand that I can't overload operator<< twice if both overloads have the same parameters, is there another way of going about this? Is there anyway perhaps in the overloaded function to use the output stream and check the name of the .txt file or something.
Hope the question makes sense.
Rather than defining an operator<< for Player itself, create a couple of utility types that refer to the Player and have their own operator<<s, let them decide which portions of the Player to stream, eg:
class Player
{
private:
std::string name;
std::string password;
int hScore;
int totalGames;
int totalScore;
int avgScore;
...
public:
...
std::string getName{} const { return name; }
...
std::string EncryptPassword(int arg) const { return ...; }
int getNumberOfScorecards() const { return ...; }
Scorecard* getScorecard(int index) const { return ...; }
class Info
{
const Player &m_player;
void print(std::ostream &os) const {
os << m_player.name << "\n" << m_player.encryptPassword(3) << "\n" << m_player.hScore << "\n";
}
public:
Info(const Player &player) : m_player(player) {}
friend std::ostream& operator<<(std::ostream &os, const Info &info)
{
info.print(os);
return os;
}
};
friend class Info;
struct Stats
{
const Player &m_player;
void print(std::ostream &os) const
{
os << m_player.totalGames << "\n" << m_player.totalScore << "\n" << m_player.avgScore << "\n";
}
public:
Stats(const Player &player) : m_player(player) {}
friend std::ostream& operator<<(std::ostream &os, const Stats &stats)
{
stats.print(os);
return os;
}
};
friend class Stats;
};
And then you can use them like this:
ofstream out("Yahtzee.txt");
if (out.is_open())
{
for(auto *player : playerList)
out << Player::Info(*player);
}
else
{
cout << "THERE WAS AN ERROR WRITING TO FILE\n";
}
for (auto *player : playerList)
{
ofstream out2(player->getName() + ".txt");
out2 << Player::Stats(*player);
for (int i = 0; i < player->getNumberOfScorecards(); ++i)
{
out2 << *player->getScorecard(i);
}
}
Online Demo
Hey guys I am new to C++ and I have a problem with this operator: (Also new in stackoverflow)
This is my class TestList:
class TestList{
public:
TestList() : listItems(10), position(0){};
TestList(int k) : listItems(k), position(0){};
int listItems;
int position;
std::vector<int> arr;
};
//my current operator is: What should be changed?
ostream& operator <<(ostream&, const TestList& tlist, int input){
os << tlist.arr.push_back(input);
return os;
}
//
int main() {
testList testlist(5);
testlist << 1 << 2 << 3; //how should I overload the operator to add these number to testlist.arr ?
return 0;
}
I hope someone could help me or can give me any tips? :)
The other answers are absolutely correct, I just want to say something general on operator<<. It always has the signature T operator<<(U, V), since it is always a binary operator, so it has to have exactly two arguments. Since the chain
a << b << c;
is evaluated as
(a << b) << c;
// That calls
operator<<(operator<<(a, b), c);
the types T and U should normally be the same, or at least compatible.
Furthermore, it is possible but very weird to assign the result of operator<< to something (like result = (a << b))). A good rule of thumb is "My code should not be weird". Therefore the type T should mostly be a reference (so X&) since otherwise it would only be a temporary copy that is unused. And that is pretty useless most of the time.
So in 90% of all cases, your operator<< should have the signature
T& operator<<(T&, V);
I think you mean the following
TestList & operator <<( TestList &tlist , int input )
{
tlist.arr.push_back( input );
return tlist;
}
Here is a demonstrative program
#include <iostream>
#include <vector>
class TestList{
public:
TestList() : listItems(10), position(0){};
TestList(int k) : listItems(k), position(0){};
int listItems;
int position;
std::vector<int> arr;
};
TestList & operator <<( TestList &tlist , int input )
{
tlist.arr.push_back( input );
return tlist;
}
std::ostream & operator <<( std::ostream &os, const TestList &tlist )
{
for ( const auto &item : tlist.arr )
{
std::cout << item << ' ';
}
return os;
}
int main()
{
TestList testlist(5);
testlist << 1 << 2 << 3;
std::cout << testlist << '\n';
return 0;
}
The program output is
1 2 3
You can even write instead of these two statements
testlist << 1 << 2 << 3;
std::cout << testlist << '\n';
only one statement
std::cout << ( testlist << 1 << 2 << 3 ) << '\n';
Pay attention to that there is a typo in your declaration
testList testlist(5);
There should be
TestList testlist(5);
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".
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