Everything was fine until I moved my objects to a namespace. And now the compiler claims that my Color attributes are private.
I thought the whole point of friends was to share encapsulated information with those a class befriends.
Color.h
friend ostream & operator << (ostream& output, const st::Color& color);
Color.cpp:
ostream & operator <<(ostream& output, const st::Color& color) {
output << "Colors:\nalpha\t: " << color.a << "\nred\t: " << color.r << "\ngreen\t: " << color.g
<< "\nblue\t: " << color.b << "\nvalue\t: " << color.color();
return output;
}
error:
Color.h||In function 'std::ostream& operator<<(std::ostream&, const st::Color&)':|
Color.h|52|error: 'unsigned char st::Color::a' is private|
Color.cpp|15|error: within this context|
Color.h|49|error: 'unsigned char st::Color::r' is private|
Color.cpp|15|error: within this context|
Color.h|51|error: 'unsigned char st::Color::g' is private|
Color.cpp|15|error: within this context|
Color.h|50|error: 'unsigned char st::Color::b' is private|
Color.cpp|16|error: within this context|
||=== Build finished: 8 errors, 0 warnings (0 minutes, 1 seconds) ===|
So what is the deal?
I'm using Code::Blocks as my IDE. And it won't even show any properties or methods when I use the dot operator on the "color" parameter. This is obviously a sign of something going wrong...somewhere.
I've taken the friend operator overloading out and it compiles just fine. No error elsewhere.
What gives?
It's declared as follows:
namespace st{
class Color {
friend ostream & operator << (ostream& output, const st::Color& color);
public:
....
private:
.....
};
};
Edit:
In my CPP I've now done this:
namespace st{
ostream & st::operator <<(ostream& output, const st::Color& color) {
output << "Colors:\nalpha\t: " << color.a << "\nred\t: " << color.r << "\ngreen\t: " << color.g
<< "\nblue\t: " << color.b << "\nvalue\t: " << color.color();
return output;
}
}
st::Color::Color() {
reset();
}
st::Color::Color(const Color& orig) {
a = orig.a;
r = orig.r;
g = orig.g;
b = orig.b;
}
void st::Color::reset() {
a = 0;
r = 0;
g = 0;
b = 0;
}
... etc
}
No compile errors, but is it normal for such a situation to use the namespace again in the header? Or is this completely off from what I should be doing?
Edit:
#Rob thanks for your input as well!
You need to declare and define your operators in the same namespace as the object as well. They will still be found through Argument-Dependent-Lookup.
A usual implementation will look like this:
/// header file
namespace foo {
class A
{
public:
A();
private:
int x_;
friend std::ostream& operator<<(std::ostream& o, const A& a);
};
std::ostream& operator<<(std::ostream& o, const A& a);
} // foo
// cpp file
namespace foo {
A::A() : x_(23) {}
std::ostream& operator<<(std::ostream& o, const A& a){
return o << "A: " << a.x_;
}
} // foo
int main()
{
foo::A a;
std::cout << a << std::endl;
return 0;
}
Edit
It seems that you are not declarin your operator<< in the namespace and are also defining it outside of the namespace. I've adjusted the code.
You need to qualify your operator with the namespace as well. It is a function signature declared in the name space so to access its symbol you need to prefix it with the namespace.
Try it like this:
namespace st {
ostream & operator <<(ostream& output, const Color & color) {
output << "Colors:\nalpha\t: " << color.a
<< "\nred\t: " << color.r
<< "\ngreen\t: " << color.g
<< "\nblue\t: " << color.b
<< "\nvalue\t: " << color.color();
return output;
}
}
Related
Overloading << for vectors works.
Overloading << for custom structs works.
The combination works as well.
But if I use the << operator on a struct with a vector of structs, compilation fails.
I made up a little example to showcase the problem:
#include <iostream>
#include <ostream>
#include <vector>
template <typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v) {
out << "[";
for (auto it = v.begin(); it != v.end(); ++it) {
out << *it;
if (std::next(it) != v.end()) {
out << ", ";
}
}
out << "]";
return out;
}
namespace xyz {
struct Item {
int a;
int b;
};
struct Aggregation {
std::vector<Item> items;
};
std::ostream& operator<<(std::ostream& out, const Item& item) {
out << "Item(" << "a = " << item.a << ", " << "b = " << item.b << ")";
return out;
}
std::ostream& operator<<(std::ostream& out, const Aggregation& agg) {
out << "Aggregation(" << "items = " << agg.items << ")";
return out;
}
} // namespace xyz
int main() {
xyz::Aggregation agg;
agg.items.emplace_back(xyz::Item{1, 2});
agg.items.emplace_back(xyz::Item{3, 4});
std::cout << agg.items << std::endl; // works: [Item(a = 1, b = 2), Item(a = 3, b = 4)]
std::cout << agg << std::endl; // fails, expected: Aggregation(items = [Item(a = 1, b = 2), Item(a = 3, b = 4))
}
Link to compiler explorer: https://godbolt.org/z/a8dccf
<source>: In function 'std::ostream& xyz::operator<<(std::ostream&, const xyz::Aggregation&)':
<source>:35:41: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'const std::vector<xyz::Item>')
35 | out << "Aggregation(" << "items = " << agg.items << ")";
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^~ ~~~~~~~~~
| | |
| | const std::vector<xyz::Item>
| std::basic_ostream<char>
In file included from /opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/iostream:39,
from <source>:1:
/opt/compiler-explorer/gcc-10.2.0/include/c++/10.2.0/ostream:108:7: note: candidate: 'std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]'
108 | operator<<(__ostream_type& (*__pf)(__ostream_type&))
| ^~~~~~~~
What am I doing wrong?
In the main function, when you write this line:
std::cout << agg.items << std::endl;
the compiler will look in the global namespace for all overloads of operator<<. The correct overload is chosen via overload resolution, and so the call works.
When you write the similar code here
std::ostream& operator<<(std::ostream& out, const Aggregation& agg) {
out << "Aggregation(" << "items = " << agg.items << ")";
return out;
}
since this code is in namespace xyz, the compiler will first look up the overloads of operator<< in namespace xyz. Once it finds any overloads at all, it will stop looking for additional overloads. However, since the actual operator<< that you want is not in namespace xyz, overload resolution fails, and you get an error.
The fix for this is to simply move the operator<< taking a vector<T> into namespace xyz.
Here's a demo.
If you actually want an operator<< that takes a vector of any type to be accessible from the global scope as well as namespace xyz, then you can define it in the global scope as you have done in your question. Then just bring the operator into xyz, or preferably, into the specific functions in namespace xyz where you need them, like this:
namespace xyz
{
// using ::operator<<; // if you want all of `xyz` to see the global overload
std::ostream& operator<<(std::ostream& out, const Aggregation& agg)
{
using ::operator<<; // if you only want the global overload to be visible in this function
out << "Aggregation(" << "items = " << agg.items << ")";
return out;
}
// ...
}
Here's a demo that shows how to stream a vector<int> as well as a vector<xyz::Item>.
Thanks to #NathanPierson for pointing out that the using declaration can be local to the functions where it's needed, instead of polluting the entirety of namespace xyz.
I ran over a similar issue again with the fmt library (https://github.com/fmtlib/fmt/issues/2093). Another working solution seems to be adding operator<< overloading for std containers directly to namespace std:
namespace std {
template <typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v) {
out << "[";
for (auto it = v.begin(); it != v.end(); ++it) {
out << *it;
if (std::next(it) != v.end()) {
out << ", ";
}
}
out << "]";
return out;
}
} // namespace std
Link to compiler explorer: https://godbolt.org/z/o7c9WP
I feel bad about adding something to namespace std though. Any thoughts on this?
I'm currently finding it impossible to fix an occurrence of infinite recursion in my code.
I have the following header that defines the Proces class:
#pragma once
#include <iostream>
class Proces {
std::string name;
int maxWaitTime;
int timeToFinish;
int timeWaited;
int timeProcessed;
public:
Proces(std::string n, int mwt = 1, int ttf = 1) :name(n), maxWaitTime(mwt), timeToFinish(ttf), timeWaited(0), timeProcessed(0) {}
bool process(int a = 1) { timeProcessed += a; return isComplete(); }
bool isComplete() { return timeProcessed >= timeToFinish; }
bool wait(int a = 1) { timeWaited += a;return maxWaitReached(); }
bool maxWaitReached() { return maxWaitTime <= timeWaited; }
friend bool operator<(const Proces& a, const Proces& b);
friend bool operator>(const Proces& a, const Proces& b);
friend std::ostream &operator<<(std::ostream &output, const Proces& a);
friend std::istream &operator>>(std::istream &input, const Proces& a);
};
Then, for the implementation of the operators, I have:
#include "proces.h"
bool operator<(const Proces & a, const Proces & b)
{
if (a.timeWaited != b.timeWaited)
return a.timeWaited < b.timeWaited;
else
return a.maxWaitTime < b.maxWaitTime;
}
bool operator>(const Proces & a, const Proces & b)
{
return ! (a < b);
}
std::ostream & operator<<(std::ostream & output, const Proces & a)
{
output << a.naziv << " MWT:" << a.maxWaitTime << " TTC:" << a.timeToFinish << " WT:" << a.timeWaited << " TP:" << a.timeProcessed;
return output;
}
std::istream & operator>>(std::istream & input,Proces & a)
{
input >> a.name >> a.maxWaitTime >> a.timeToFinish;
a.timeWaited = 0;
a.timeProcessed = 0;
return input;
}
This lead to two (as far as I know unrelated) problems:
Use of the output operator lead to said infinite recursion happening
The code itself cannot be compiled without commenting out the implementation
of the input operator as it claims the fields of the class are inaccessible
in spite of being a friend of the class
Severity Code Description Project File Line Suppression State
Error (active) E0265 member "Proces::name" (declared at line 4 of "[project path]\proces.h") is inaccessible aspdz2 [project path]\proces.cpp
Here is the main function (the < and > operators work as intended):
#include "proces.h"
int main() {
Proces a{ "Glorious prces",1,2 };
Proces b{ "Glorious prces2",2,2 };
if (a < b)std::cout << "A is lesser" << std::endl;
else std::cout << "B is lesser" << std::endl;
if (a > b)std::cout << "A is greater" << std::endl;
else std::cout << "B is greater" << std::endl;
b.wait(-1);
if (a < b)std::cout << "A is lesser" << std::endl;
else std::cout << "B is lesser" << std::endl;
//Infinite recursion happens here:
std::cout << b << std::endl;
}
It appears that the reason for the
Severity Code Description Project File Line Suppression State Error (active) E0265 member "Proces::name" (declared at line 4 of "[project path]\proces.h") is inaccessible aspdz2 [project path]\proces.cpp
error was due to the accidental inclusion of the const keyword in the declaration of the >> operator;
The recursion on the other hand was happening because I forgot to#include<string>
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 don't know why cout << da << '\n' works fine,but std::cout << next_Monday(da) << '\n' went wrong. Why the direct Date object can output, but the return Date can't.
Why overloaded operator << works sometimes but other times doesn't.
here is my code..
#include <iostream>
#include <stdlib.h>
struct Date {
unsigned day_: 5;
unsigned month_ : 4;
int year_: 15;
};
std::ostream& operator<<(std::ostream& out,Date& b)
{
out << b.month_ << '/' << b.day_ << '/' << b.year_;
return out;
}
std::istream& operator>>(std::istream& in,Date& b);
Date next_Monday(Date const &d);
int main()
{
Date da;
std::cin >> da;
std::cout << da << '\n';
std::cout << next_Monday(da) << '\n';
return 0;
}
this is what clang said: (I use g++ to invoke)
excercise19DateManipulate.cpp:114:18: error: invalid operands to binary
expression ('ostream' (aka 'basic_ostream<char>') and 'Date')
std::cout<< next_Monday(da) <<'\n';
~~~~~~~~^ ~~~~~~~~~~~~~~~
Because you can't bind a temporary to a non-const lvalue reference. Change the operator to take a const reference:
std::ostream& operator<<(std::ostream& out, const Date& b)
You never defined the "next_Monday()" function as far as I can see, you only declared it.
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)