Finding the mistake in C++ operator overloading - c++

I am trying to understand how to overload the '<<' operator. So i wrote a simple test code that I report part of if here:
class Buffer {
vector<char> buffer;
...
ostream& operator<< (ostream& out, const vector<char>& v) {
out << "[";
size_t last = v.size() - 1;
for(size_t i = 0; i < v.size(); ++i) {
out << v[i];
if (i != last)
out << ", ";
}
out << "]";
return out;
}
...
};
The way I use the class in the main is the usual but I get the following error. Why?
main.cpp:22:10: error: overloaded 'operator<<' must be a binary operator (has 3 parameters)
ostream& operator<< (ostream& out, const vector<char>& v) {
^

It needs to be a binary operator: Since you're adding the operator as a class member, it'll always be called on a instance of that class, like this:
Buffer myBuffer;
const vector<char> myVector;
myBuffer << myVector;
You should see this as a function equivalent to:
myBuffer.DoOperator(myVector);
.. which takes only one argument, not two! So you should skip the first argument!

class Buffer {
vector<char> buffer;
...
friend
ostream& operator<< (ostream& out, const Buffer& b) {
const vector<char>& v=b.buffer;
out << "[";
size_t last = v.size() - 1;
for(size_t i = 0; i < v.size(); ++i) {
out << v[i];
if (i != last)
out << ", ";
}
out << "]";
return out;
}
...
};

Related

Getting error when overloading << operator

I have a Class called "Vector". It consists of two private fields: std::vector<double> coordinates and int len. Methoddim() returns len.
I am overloading operator << like that:
friend std::ostream& operator<<(std::ostream& os, Vector& vec )
{
std:: cout << "(";
for ( int i = 0; i < vec.dim(); i++ ) {
if ( i != vec.dim()-1){
os << vec[i] << ", ";
} else {
os << vec[i];
}
}
os << ')';
return os;
}
An operator + like that:
friend Vector operator +(Vector& first, Vector& second)
{
if(first.dim() != second.dim()){
throw std::length_error{"Vectors must be the same size"};
}else {
Vector localVec(first.dim()); // same as {0,0,0...,0} - first.dim() times
for (int i = 0; i < first.dim(); i++){
localVec[i] = first[i] + second[i];
}
return localVec;
}
}
And operator [] like that:
double& operator[](int index)
{
return this->coordinates[index];
}
And here's the problem:
Vector x{1,2,4};
Vector y{1,2,3};
Vector z = x + y;
std:: cout << z; // it works perfectly fine - (2, 4, 7)
std:: cout << x + y; // it gives me an error
could not match 'unique_ptr<type-parameter-0-2, type-parameter-0-3>' against 'Vector'
operator<<(basic_ostream<_CharT, _Traits>& __os, unique_ptr<_Yp, _Dp> const& __p)
It seems to me that this error is related to parameter Vector& vec , but I don't know whether it's right and what should I do to fix it. If anyone could give me a hint (or tell me what I should read more about) - I would be very grateful.
Here's full code:
class Vector
{
private:
std::vector <double> coordinates;
int len;
public:
Vector(): len{0}, coordinates{} {};
Vector(std::initializer_list <double> coordinates_): len{static_cast <int>( coordinates_.size())}, coordinates{coordinates_} {}
Vector(int len) : len{len} {
for(int i = 0; i < len; i++){
coordinates.push_back(0);
}
}
int dim() const
{
return this->len;
}
double& operator[](int index)
{
return this->coordinates[index];
}
friend std::ostream& operator<<(std::ostream& os, Vector& vec )
{
std:: cout << "(";
for ( int i = 0; i < vec.dim(); i++ ) {
if ( i != vec.dim()-1){
os << vec[i] << ", ";
} else {
os << vec[i];
}
}
os << ')';
return os;
}
friend Vector operator +(Vector& first, Vector& second)
{
if(first.dim() != second.dim()){
throw std::length_error{"Vectors must be the same size"};
}else {
Vector localVec(first.dim());
for (int i = 0; i < first.dim(); i++){
localVec[i] = first[i] + second[i];
}
return localVec;
}
}
};
friend std::ostream& operator<<(std::ostream& os, Vector& vec)
This signature doesn't accept rvalues, and this is why the error happens for your temporary result here:
std:: cout << x + y;
Change the second parameter into const Vector& vec or provide an overload with an r-value reference parameter.
friend std::ostream& operator<<(std::ostream& os, const Vector& vec);
A temporary cannot bind to a non-const reference argument. You are missing const in at least two places. Most importantly here:
friend std::ostream& operator<<(std::ostream& os, const Vector& vec )
// ^^
And there should a const overload of operator[]

Use of std::vector results in unknown output C++

I'm unable to figure out why the output I received isn't just "00110" but has other giberrish characters in it. Not sure what's wrong with my vector push_back.. It definitely makes sense to me. If I changed it to std::string implementation, it would give a correct output. But in this case, I would need to use vector for proper encapsulation of the object's state. I've been debugging for a few hours now, but still can't find out why. Hope anyone is able to help! Thanks! Note: main() can't be modified.
#include <iostream>
#include <vector>
template<size_t NumBits>
class bitsetts
{
private:
static const unsigned int NO_OF_BITS = CHAR_BIT * sizeof(int); //32 bits
static const unsigned NumBytes = (NumBits - 7) /8;
unsigned char array[NumBytes];
public:
bitsetts() { }
void set(size_t bit, bool val = true) {
if (val == true)
{
array[bit] |= (val << bit );
}
else
{
array[bit] &= (val << bit );
}
}
bool test(size_t bit) const {
return array[bit] & (1U << bit );
}
const std::string to_string()
{
std::vector<char> str;
for (unsigned int i=NumBits; i-- > 0;)
str.push_back('0' + test(i));
return str.data();
}
friend std::ostream& operator<<(std::ostream& os, const bitsetts& ob)
{
for (unsigned i = NumBits; i-- > 0;)
os << ob.test(i);
return os << '\n';
}
};
int main()
{
try
{
bitsetts<5> bitsetts;
bitsetts.set(1);
bitsetts.set(2);
const std::string st = bitsetts.to_string();
if (st != "00110")
{
std::cout << st << std::endl;
throw std::runtime_error{ "-" };
}
}
catch (const std::exception& exception)
{
std::cout << "Conversion failed\n";
}
}
You are filling the std::vector with char values and then constructing a std::string from the raw char data using the std::string constructor that takes a single const char* parameter. That constructor expects the char data to be null-terminated, but you are not pushing a null terminator into your vector, which is why you get extra garbage on the end of your std::string.
So, either push a null terminator into the vector, eg:
const std::string to_string()
{
std::vector<char> str;
for (unsigned int i=NumBits; i-- > 0;)
str.push_back('0' + test(i));
str.push_back('\0'); // <-- add this!
return str.data();
}
Or, use a different std::string constructor that can take the vector's size() as a parameter, eg:
const std::string to_string()
{
std::vector<char> str;
for (unsigned int i=NumBits; i-- > 0;)
str.push_back('0' + test(i));
return std::string(str.data(), str.size()); // <-- add size()!
}
On a side note: your to_string() method should be marked as const, eg:
const std::string to_string() const
Which would then allow you to use to_string() inside of your operator<<, eg:
friend std::ostream& operator<<(std::ostream& os, const bitsetts& b)
{
return os << b.to_string() << '\n';
}

How to overload << for a vector of structures

I'm having trouble with the syntax for a homework program. The prompt is to overload an inserter in such a way that it can properly execute the program fragment:
for (int i = 0; i < v.size(); ++i)
cout << v[i] << endl;
cout << endl;
So, this is what I have so far, but I still get an error at the cout << v[i] statement (Invalid operands to binary expression):
unsigned int seed;
struct node
{
int integer;
double value;
};
double random(unsigned int &seed);
void initialize_vector(vector<node> &v);
template<typename T>
void print_vector(const vector<T> &v);
template<typename T>
ostream &operator <<(ostream &out, const vector<T> &v);
template<typename T>
void output(ostream &out, const vector<T> &v);
int main()
{
vector<node> v(10);
initialize_vector(v);
print_vector(v);
return 0;
}
double random(unsigned int &seed)
{
const int MODULUS = 15749;
const int MULTIPLIER = 69069;
const int INCREMENT = 1;
seed = ((MULTIPLIER * seed) + INCREMENT) % MODULUS;
return double(seed) / double(MODULUS);
}
void initialize_vector(vector<node> &v)
{
for (int i = 0; i < v.size(); ++i)
{
v[i].integer = int (11 * random(seed));
v[i].value = double (11 * random(seed));
}
}
template<typename T>
void print_vector(const vector<T> &v)
{
for (int i = 0; i < v.size(); ++i)
cout << v[i] << endl;
cout << endl;
}
template<typename T>
ostream &operator <<(ostream &out, const vector<T> &v)
{
output(out, v);
return (out);
}
template<typename T>
void output(ostream &out, const vector<T> &v)
{
cout << v.integer;
cout << setprecision(2) << fixed << setw(6) << v.value;
}
I've tried passing node instead of T, along with passing with and without const references for the last 3 functions, so again I assume my syntax in the void output function is wrong somehow. Any help or points in the right direction would be greatly appreciated.
*Note: I can't change the ostream &operator function.
cout << v[i] << endl;
If v is a vector of node, then you need one more function to overload operator << for a node
ostream &operator <<(ostream &out, const node &n)
{
out << n.interger << " " << n.value;
return out;
}

Macro Overloading with Different Signatures

Is it possible to overload macros that can perform different operators (=, +=, -=, ++, --, etc) with the same macro name?
I would like to achieve something like this:
int main() {
LOG_STAT("hello") << "world";
LOG_STAT("hello") = 5;
LOG_STAT("hello") += 10;
}
I tried the following and the issue I am having is that I can not redeclare the macro LOG_STAT as it has already been defined. Sample code below, hopefully you get the idea.
#define LOG_STAT(x) Stat(x).streamAdd()
#define LOG_STAT(x) Stat(x).add() // redeclare error here
class Stat {
public:
Stat(const char *type_ ) : type(type_) {}
~Stat(){ std::cout << type << " " << stream.str().c_str() << " " << number << std::endl;}
int& add() { return number; }
std::ostringstream& streamAdd() { return stream; }
const char * type;
int number;
std::ostringstream stream;
};
Create operators for your class:
Stat& Stat::operator += (int rhs)
{
number += rhs;
return *this;
}
Stat operator + (const Stat& lhs, int rhs)
{
Stat res(lhs);
res += rhs;
return res;
}
template <typename T>
Stat& operator << (Stat& stat, const T&value)
{
stat.stream << value;
return stat;
}
Then you may directly use
Stat("hello") << "world";
Stat("hello") = 5;
Stat("hello") += 10;
(You may still use your MACRO with #define LOG_STAT Stat)

Print out inherited structured list c++

If I have this code
struct Unit{
int coef; //coefficient
int exp; //exponent
};
class Func: private std::list<Unit>{
public:
Func();
friend std::ostream& operator<<(std::ostream &, Func);
};
How do I print it out?
I tried using the concept from here: http://www.cplusplus.com/forum/beginner/5074/
But without success:
ostream& operator<<(ostream &output, Func &pol)
{
list<Unit>::iterator i;
for( i = pol.begin(); i != pol.end(); ++i)
{
Unit test = *i;
output << test.coef << " ";
}
return output;
}
And do I initialize it correctly?
Func::Func()
{
Unit test;
test.coef = 0;
test.exp = 0;
Func::push_back(test);
}
Sorry. New to this about inheritance. Though it wasn't hard when it was about the classes I made myself.
Updated code:
struct Unit{
int coef; //coefficient
int exp; //exponent
Unit():coef(0),exp(0){}
};
class Func : public std::list<Unit>{
public:
Func();
friend std::ostream& operator<<(std::ostream &, const Func &);
};
Func::Func()
{
Unit test;
Func::push_back(test);
}
ostream& operator <<(std::ostream &output, const Func& pol)
{
for (list<Unit>::const_iterator i = pol.begin(); i != pol.end(); output << i->coef << " " << i->exp << " ", ++i);
return output;
}
It is not clear for me what do you want to do. Is is a requirement that you inherit from an STL list? I wouldn't do it.
But this at least would be a solution.
struct Unit{
int coef; //coefficient
int exp; //exponent
};
std::ostream& operator<<(std::ostream &os, Unit const& v)
{
os << v.coef << " " << v.exp << std::endl;
return os;
}
int main()
{
std::list<Unit> myList;
Unit element;
element.coef = 0;
element.exp = 0;
myList.push_back(element);
std::ostringstream os;
for (std::list<Unit>::const_iterator it = myList.begin(); it != myList.end(); ++it)
{
os << *it;
}
std::cout << os.str() << std::endl;
}
With C++11 this could be implemented much nicer, but I don't know what compiler you are using. I did not compile it so far, just hacked it down; so sorry for syntax errors.
First, regarding your printing. You can do it a number of ways, the most robust being defining free operators for each type. Such as:
struct Unit{
int coef; //coefficient
int exp; //exponent
};
std::ostream& operator <<(std::ostream& os, const Unit& unit)
{
os << unit.coef << "X^" << unit.exp;
return os;
}
The function is a little more complex. You would be better served to use the list as a member variable and provide an operator for stream insertion for that class. Such as:
#include <iostream>
#include <iterator>
#include <list>
#include <cstdlib>
struct Unit
{
int coef; //coefficient
int exp; //exponent
Unit(int coef, int exp=0)
: coef(coef), exp(exp)
{}
friend std::ostream& operator <<(std::ostream&, const Unit&);
};
std::ostream& operator <<(std::ostream& os, const Unit& unit)
{
os << unit.coef << "X^" << unit.exp;
return os;
}
class Func
{
public:
std::list<Unit> units;
friend std::ostream& operator <<(std::ostream&, const Func&);
};
std::ostream& operator <<(std::ostream& os, const Func& func)
{
std::copy(func.units.begin(), func.units.end(),
std::ostream_iterator<Unit>(os, " "));
return os;
}
int main()
{
Func func;
func.units.push_back(Unit(3, 2));
func.units.push_back(Unit(2, 1));
func.units.push_back(Unit(1, 0));
std::cout << func << endl;
return EXIT_SUCCESS;
}
Output
3X^2 2X^1 1X^0
Note: I did NOT properly hide members, provide accessors, etc. That I leave to you, but the general idea on how to provide output-stream operators should be obvious. You could significantly further enhance the output operator for a `Unit by:
Not printing exponents of 1
Only printing the coefficient for exponents of 0 (no X),
Not printing a 1 coefficient of any term with an exponent greater than 0
Not printing anything for terms with 0 coefficients.
These tasks I leave to you.