How to overload the operator << inside a structure - c++

I just want to print the two values of my structure, but can't compile my code - I get: no operator “<<” matches these operands.
#include <iostream>
using namespace std;
struct SCoor
{
int i, j;
bool operator == (const SCoor & tmp) const
{
return (i == tmp.i && j == tmp.j);
}
bool operator < (const SCoor & tmp) const
{
return (i < tmp.i || (i == tmp.i && j < tmp.j));
}
ostream& operator << (ostream &o) {
return o << i << " " << j;
}
};
int main()
{
SCoor tmp = { 3, 3 };
cout << tmp;
return 0;
}
How do I have to overload the operator "<<"?

You overload the << operator as a member function if you want your structure to be on the left hand side of the expression. So:
struct SCoor
{
// ...
SCoor& operator << (Stuff const& s) {
// ...
return *this;
}
};
// ...
Stuff stuff;
SCoor scoor;
scoor << s; // insert s into my SCoor
If you want to make your struct the right hand side of the << expression you have to define a standalone function:
std::ostream& operator<<(std::ostream& os, SCoor const& scoor)
{
return os << scoor.i << " " << scoor.j;
}
However it is quite common to make the external function a friend function and to define it in the struct definition:
struct SCoor
{
// ...
friend std::ostream& operator<<(std::ostream& os, SCoor const& scoor)
{
return os << scoor.i << " " << scoor.j;
}
};
// ...
SCoor scoor;
std::cout << scoor << '\n';
But it is not a member of your struct, it is just defined inside its definition for convenience.

Related

Output of map of set custom objects c++

So I have a map that has user defined keys and the values in it are sets of objects too. So I'm trying to write some print function but I have no idea how to do that. (I'm kind of new to maps and sets).
My problem function:
void print() const
{
for (auto& itr : my_mmap)
{
std::cout << "Key for this set:" << itr.first << "\n\n";
for (int i = 0; i< itr.second.size(); i++)
{
std::cout << itr.second[i] << std::endl;
}
}
}
Here's my class:
#include <iostream>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <set>
class Enclosing {
private:
class Key {
int m_number;
std::string m_name;
public:
Key(int num, std::string name) :m_number(num), m_name(std::move(name)) {};
bool operator<(const Key& rhs) const {
return std::tie(m_number, m_name) < std::tie(rhs.m_number, rhs.m_name);
}
friend std::ostream& operator<<(std::ostream& os, const Key& k) {
return os << '{' << k.m_number << ',' << k.m_name << '}';
}
};
class Nested {
std::string m_str;
double m_dbl;
bool m_boolean;
public:
Nested(std::string str, double dbl, bool boolean) :m_str(std::move(str)), m_dbl(dbl), m_boolean(boolean) {};
friend std::ostream& operator<<(std::ostream& os, const Nested& n) {
return os << '{' << n.m_str << ',' << n.m_dbl << ',' << n.m_boolean << '}';
}
};
std::multimap<Key, std::set<Nested>> my_mmap;
public:
template <class... Args>
void add_new_object_to_mmap(Args&&... args) {
my_mmap.emplace(std::piecewise_construct, std::forward<Args>(args)...);
}
/*
THAT PROBLEM FUNCTION
*/
void print() const
{
for (auto& itr : my_mmap)
{
std::cout << "Key for this set:" << itr.first << "\n\n";
for (int i = 0; i< itr.second.size(); i++)
{
std::cout << itr.second[i] << std::endl;
}
}
}
static Enclosing& get_singleton() {
static Enclosing instance;
return instance;
}
};
}
So the problem is that I am getting an error "no operator "[]" match these operands". How can I output my map and set in the best way?
The problem is that we cannot use indexing on a std::set. Thus itr.second[i] is not valid because itr.second is an std::set.
To solve this you can use a range-based for loop as shown below:
for (const auto&elem:itr.second)
{
std::cout << elem << std::endl;
}

C++ insertion operator for class method

In C++ is there a way to use the insertion operator for a class method?
This operator<< overload is working:
class Complex {
public:
//Normal overload:
friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
out << "test overload";
return out;
}
Complex() {};
~Complex() {};
};
I can do this:
int main()
{
Complex* o = new Complex();
std::cout << "This is test: " << *o << "." << std::endl; // => This is test: test overload.
}
I know about stream manipulators, like this:
std::ostream& welcome(std::ostream& out)
{
int data = 1;
out << "WELCOME " << data << "\r\n";
return out;
}
int main()
{
std::cout << "Hello " << welcome; // => "Hello WELCOME 1\r\n"
}
How can I put the welcome method into the Complex class and then how shall I call it from cout (please note that welcome method must access some class member variables)?
My trial:
class Complex {
public:
//Normal overload:
friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
out << "test overload";
return out;
}
std::ostream& welcome(std::ostream& out) {
out << "WELCOME " << data << "\r\n";
return out;
}
Complex() { data = 1; };
~Complex() {};
private:
int data;
};
int main()
{
Complex* o = new Complex();
std::cout << "This is test2: " << o->welcome << std::endl; // compile error
}
One easy way to pick a different << overload is to use a different type.
#include <iostream>
class Complex {
public:
//Normal overload:
friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
out << "test overload";
return out;
}
struct extra_info {
const Complex& parent;
extra_info(const Complex& p) : parent(p) {}
friend std::ostream& operator<<(std::ostream& out, const extra_info& ei){
int i = 1;
out << "extrainfo " << i;
return out;
}
};
extra_info extrainfo() {
return {*this};
}
Complex() {};
~Complex() {};
};
int main() {
Complex c;
std::cout << c << "\n";
std::cout << c.extrainfo();
}
Output:
test overload
extrainfo 1
I suppose in your real code you are using members. Hence the helper type must hold a reference to the Complex instance.

why is cout calling parent operator<< instead of child operator<< [duplicate]

This question already has answers here:
C++ Overloading operator << for child classes
(2 answers)
Closed 2 years ago.
I have 3 classes, and I'd like each one to print out differently to the terminal, I have a node class that represents a vertex in a BDD graph, right now I'm trying to write code to do logical operations on the nodes.
The Node class is setup as such:
class Node {
char name;
public:
Node() { name = '0'; }
Node(char c) { name = c; }
Node(const Node& n) { name = n.name; }
friend ostream& operator<<(ostream& stream, const Node& n);
};
ostream& operator<<(ostream& stream, const Node& n) {
return stream << "{ Node " << n.name << " }";
}
The operator classes are setup as such:
class Operation {
public:
Node result;
friend std::ostream& operator<<(std::ostream& stream, const Operation& op);
Operation() {}
Operation(const Operation& op) { cout << "Copying " << *this << endl; }
virtual ~Operation() { cout << "Destroying " << *this << endl; }
virtual Node compute() {
cout << "Computing " << *this << endl;
result = Node('1');
return result;
}
};
std::ostream& operator<<(std::ostream& stream, const Operation& op) {
return stream << "Operation { Unspecified }";
}
class UnaryOperation : public Operation {
public:
Node arg1;
UnaryOperation(const Node& arg1) { this->arg1 = arg1; }
UnaryOperation(const UnaryOperation& op) : Operation::Operation(op) {
arg1 = op.arg1;
}
virtual ~UnaryOperation() {}
friend ostream& operator<<(ostream& stream, const UnaryOperation& op);
};
ostream& operator<<(ostream& stream, const UnaryOperation& op) {
return stream << "Operation { arg1: " << op.arg1 << " }";
}
class BinaryOperation : public UnaryOperation {
public:
Node arg2;
BinaryOperation(const Node& arg1, const Node& arg2) : UnaryOperation(arg1) {
this->arg2 = arg2;
}
BinaryOperation(const BinaryOperation& op) : UnaryOperation::UnaryOperation(op) {
arg2 = op.arg2;
}
virtual ~BinaryOperation() {}
friend ostream& operator<<(ostream& stream, const BinaryOperation& op);
};
ostream& operator<<(ostream& stream, const BinaryOperation& op) {
return stream << "Operation { arg1: " << op.arg1 << ", arg2: " << op.arg2;
}
For debugging reasons, these messages need to print out as such, but when I run this
Node apply(Operation& op) {
cout << "Performing apply operation on " << op << endl;
op.compute();
return op.result;
}
int main() {
Node a('a'), b('b');
UnaryOperation uop(a);
BinaryOperation bop(a, b);
cout << uop << endl;
cout << bop << endl;
apply(uop);
apply(bop);
}
I get
Operation { arg1: { Node a } }
Operation { arg1: { Node a }, arg2: { Node b }
Performing apply operation on Operation { Unspecified }
Computing Operation { Unspecified }
Performing apply operation on Operation { Unspecified }
Computing Operation { Unspecified }
Destroying Operation { Unspecified }
Destroying Operation { Unspecified }
Needless to say, this is not very helpful for debugging.
Why is it doing this, and how do I fix it?
The friend function is not virtual. It is selected according to the type of the second argument.
In this function
Node apply(Operation& op) {
cout << "Performing apply operation on " << op << endl;
op.compute();
return op.result;
}
the type of the argument is Operation &. So in this statement
cout << "Performing apply operation on " << op << endl;
there is called the friend function for an object of the type Operation &.
You could make the friend function "virtual" the following way as it is shown in the demonstrative program below.
#include <iostream>
class Operation
{
public:
virtual ~Operation() = default;
private:
virtual std::ostream & out( std::ostream &os = std::cout ) const
{
return os << "This is an Operation";
}
friend std::ostream& operator <<( std::ostream &stream, const Operation &op )
{
return op.out( stream );
}
};
class UnaryOperation : public Operation
{
std::ostream & out( std::ostream &os = std::cout ) const override
{
return os << "This is an Unary Operation";
}
friend std::ostream& operator <<( std::ostream &stream, const UnaryOperation &op )
{
return op.out( stream );
}
};
class BinaryOperation : public UnaryOperation
{
std::ostream & out( std::ostream &os = std::cout ) const override
{
return os << "This is a Binary Operation";
}
friend std::ostream& operator <<( std::ostream& stream, const BinaryOperation &op )
{
return op.out( stream );
}
};
void f( const Operation &op )
{
std::cout << op << '\n';
}
int main()
{
BinaryOperation bop;
f( bop );
return 0;
}
Its output is
This is a Binary Operation

Issues with trying to create a generic data type with classes C++

I am having an issue with my C++ program. Right now I am just trying to create a generic "variable" utilizing operator overloading. So the issues is when I determine
the type of data passed. (I must do this because I am later overloading the << operator so that ostream can output the correct data) The conditional statement
does not work as expected. Here is the code
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = 5;
std::cout << var << std::endl;
return 0;
}
That should be the final code once that class is done. But the error persists when I try to set var = blah. It gives cannot convert const char* to int or
cannot convert char to int or anything of the sort. It was my impression that that code does not matter at all if it is not true. If I comment out the part
where I set the correct variables it runs with no issue
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; //in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; //str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; //fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; //fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; //ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl;
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = "Hello world";
std::cout << var << std::endl;
return 0;
}
This runs, but only when I comment var = blah as shown above. So how can I fix this? Again it was my understanding that if the if statement is not true
the code inside wont even run. But it seem to anyway. I do not understand why this is happening. Can someone shed some light on it? Basically all I want to
do is create a "generic data type" and use the operator=() to set it.
I understand the need is to be able to declare:
SLVar var;
and later decide to assign integer, string, float, whatever without the need of fixing the type by a template (kind of dynamic typing)
I'm proposing a solution with a lot of compromises, without typeinfo at all and without templates (the template is useless here since you have to perform a type check within the function)
either, I kept only const char * and int types for simplicity's sake but that can be easily extended.
When assigning, the type is set in an enumerate, later used by the console write function.
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
private:
const char* str;
int in;
enum TheType { TYPE_INT, TYPE_CHARPTR, TYPE_UNKNOWN };
TheType type;
public:
SLVar() : type(TYPE_UNKNOWN)
{}
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
SLVar & operator=(int var)
{
in = var;
type=TYPE_INT;
return *this;
}
SLVar &operator=(const char *var)
{
str = var;
type=TYPE_CHARPTR;
return *this;
}
};
std::ostream& operator<<(std::ostream& os, const SLVar& var)
{
switch (var.type)
{
case SLVar::TYPE_CHARPTR:
return os << var.str;
case SLVar::TYPE_INT:
return os << var.in;
default:
return os; // not printing anything
}
}
int main()
{
SLVar var;
var = "Hello world";
std::cout << var << std::endl;
var = 35; // kind of dynamic typing through assignment
SLVar var2;
var2 = 56;
std::cout << var << " " << var2 << std::endl;
}
result:
Hello world
35 56
It's still missing a lot of things, like default constructor, copy constructor... but the principle works.
Try something along the lines of:
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
template <typename T>
class SLVar {
public:
SLVar<T>() {} ; // Defualt constructor
SLVar<T>(T value) :
var(value)
{} ;
T var ;
T getvalue() {return var ;}
// This lets you use the class as though it was the object
inline operator T() {return var;}
T operator=(T newvar)
{
var = newvar ;
}
};
int main()
{
SLVar<double> var_dbl(3.14);
SLVar<int> var_int(5) ;
SLVar<const char*> var_str("hello") ;
SLVar<char> var_char('y') ;
// And now to test...
std::cout << "Dbl: " << var_dbl << std::endl;
std::cout << "Int: " << var_int << std::endl;
std::cout << "Str: " << var_str << std::endl;
std::cout << "Char: " << var_char << std::endl;
// Lets try resetting the values
var_dbl = 4.6 ;
var_int = 7 ;
var_str = "goodbye" ;
var_char = 'n' ;
std::cout << "Dbl: " << var_dbl << std::endl;
std::cout << "Int: " << var_int << std::endl;
std::cout << "Str: " << var_str << std::endl;
std::cout << "Char: " << var_char << std::endl;
// Lets try some math on the double variable
std::cout << "Dbl * 0.5: " << var_dbl*0.5 << " (this shoudl be 2.3)" << std::endl;
return 0;
}
The downside is that (I'm I'm sure you've realized) the streamer wont work if you try to do SLVar<std::string>. There you just need to use SLVar<const char*>. I've also added the line:
inline operator T() {return var;}
So that the the class can act as an object of the type it is suppose to represent. So you can use the SLVar<double> as a double in a formula, for example.

Upcasting and Stream Operator Overloading

As you can see, only the overloaded version of the stream insertion operator for the base class is called on both instances. I understand why it's so. It's because there is no dynamic binding. But, how do I fix it?
#include <iostream>
using namespace std;
class A {
int i;
char c;
public:
A(int i = 0, char c = ' ') {
this->i = i;
this->c = c;
}
int getI() { return i; }
char getC() { return c; }
friend ostream& operator << (ostream&, A&);
};
class B : public A {
double d;
public:
B(int i = 0, char c = ' ', double d = 0.0) : A(i, c), d(d) {}
friend ostream& operator << (ostream&, B&);
};
ostream& operator << (ostream& out, A& a) {
out << "\nInteger: " << a.i << "\nCharacter: " << a.c << endl;
return out;
}
ostream& operator << (ostream& out, B& b) {
out << "\nInteger: " << b.getI() << "\nCharacter: " << b.getC() << "\nDouble: " << b.d << endl;
return out;
}
int main() {
A* a = new A (10, 'x');
B* b = new B(20, 'y', 5.23);
A* array[] = { a, b };
cout << *(array[0]);
cout << "\n______________________________\n";
cout << *(array[1]);
delete a;
delete b;
cin.get();
return 0;
}
How can I make cout << *(array[1]); call the overloaded stream insertion operator that takes an object of B as one of it's arguments?
You can't make it call the overloaded operator, since overloading is resolved at compile time.
To do resolution at runtime, i.e. use dynamic dispatch, you need to move the code that does the printing to a virtual member function.
Then call that from the operator (you only need one, for the base class).
class A
{
public:
// ...
// Override this in B
virtual void print(std::ostream& o) const
{
o << "\nInteger: " << i << "\nCharacter: " << c << endl;
}
// ...
};
ostream& operator << (std::ostream& out, const A& a) {
a.print(out);
return out;
}