Declaring = and [] operators for a class on the header file, "must be a nonstatic member function" error - c++

I've made a class Block and a struct coords and while implementing the operators i came up with the errors:
'coords operator[](const Block&, const size_t&)' must be a nonstatic member function
'bool operator=(Block&, const Block&)' must be a nonstatic member function
I've declared these 2 in the header file of the class Block as follows:
class Block
{
friend Block operator+(const Block&, const coords&);
friend Block operator+(const Block&, const Block&);
friend coords operator[](const Block&, const std::size_t&);
friend void operator+=(Block&, const coords&);
friend void operator+=(Block&, const Block&);
friend bool operator=(Block&, const Block&);
//...
};
Only the operators [] and = get this error, and I'm not sure why.
I've tried to change the return value and parameter types but it keeps getting the same problem.
Are these two operators special? Or is there an error on my declarations?
I've searched for ways to solve this problem, but couldn't find a suitable answer.
Thank you for the replies.

Not all operators can be overloaded using non-member functions. [] and = are two such operators. They can be overloaded only as member functions.
See http://en.cppreference.com/w/cpp/language/operators for more details.

Those operators cannot be declared as friends. Instead you should declare like this:
coords operator[](const std::size_t&);
bool operator=(const Block&);
Your operators are also not really following conventions. Operators += and = should be returning a Block& namely *this.

The reason is exactly what the error message says: those two have to be non-static member functions. Get rid of the friend from in front of them and remove the first argument.
Further, operator+= is usually implemented as a member function, too, although it doesn't have to be. But if it is, it gives you an easy way to implement operator+ without making it a friend.

#R Sahu's link was useful, showing that [] and = can no be declared as non-member, but it didn't really explain why.
#Baum mit aguen's link cleared some other questions too.
(Thanks for the information)
So, I adjusted my code to this new information as follows:
Block.h
class Block
{
public:
//...
coords* operator[](size_t);
Block operator=(Block);
//...
};
Block.cpp
//...
coords* Block::operator[](size_t index)
{
if(index >= 0 && index < block.size())
return &block.at(index);
coords *tmp = new coords(-1, -1);
return tmp;
}
Block Block::operator=(Block b2)
{
block.empty();
block.reserve(b2.block.size());
append(b2.block);
return *this;
}
//...
This way you can call *(*b1)[0] = c1; being Block* b1 and coords c1.
The friend modifier is useful for other types of implementations, although I only realized after that the implementation of inline had to be done in the header file, not on the cpp.
Block.h
class Block
{
public:
//...
friend std::ostream& operator<<(std::ostream&, const Block&);
friend std::ostream& operator<<(std::ostream&, Block&);
//...
};
inline std::ostream& operator<<(std::ostream& out, const Block& b)
{
// do something
return out;
};
inline std::ostream& operator<<(std::ostream& out, Block& b)
{
// do something
return out;
};
In this case, you need to pass the "this" parameter has to be passed to the function also as these are non-member functions and should be implemented outside the class, in the header file.
I hope this helps, good coding everyone.

Related

Overloading specialized assignment operator based on typename

Okay, the title is a mouthful and hopefully specific enough, but I'm running into a C++ issue which I think is possible, I just can't seem to find the proper syntax.
I have a simple template-based property class:
template <typename T>
class Property
{
public:
Property<T> &operator = (const T &src)
{
m_data = src;
return *this;
};
operator const T& () const
{
return m_data;
}
private:
T m_data;
};
I need to assign values from a QVariant, which is also sort of a property but without templates. At the moment I am deferencering the values explicitly when assigning:
Property<QString> p1;
Property<int> p2;
p1 = var1.toString();
p2 = var2.toInt();
This works but it is tedious and I'm sure the compiler can do the work for me. So, I tried implementing specialized assignment operators based on the typename of the Property; in other words, if the template specialization is based on a QString use one function, if it is based on an int use another function, et cetera.
I tried things like:
Property<QString> &operator = (const QVariant &ref)
{
m_data = ref.toString ();
return *this;
};
or...
template <typename int> &Property<int>::operator = (const QVariant &ref)
{
m_data = ref.toInt ();
return *this;
};
or...
template<> Property<T> &Property<QString>::operator = (const QVariant &ref)
{
m_data = ref.toString ();
return *this;
}
..both inside and outside of the class declaration but to no avail. I get errors like "expected nested-name-specifiers", "two or more data types in declaration of parameters" and the like.
Any pointers to the correct syntax would be appreciated!
PS: the first declaration compiles witout error, but adding the same declaration for <int> makes it ambiguous since only the return type differs.
Compiler is GCC 4.8.2 with --stdc=c++11 enabled.
Although the answer of paddy seems correct, it seems to me tedious to generalize it (implement a specialzed assignment operator to all the types that a QVariant can hold, in addition to QString and int).
An easier solution would be to specialize the assignment operator once for all, in a way that benefits from the built-in conversions that the QVariant provides:
Property& operator= (const QVariant& src)
{
assert(src.canConvert<T>());
m_data = src.value<T>();
return *this;
}
The original class definition is a bit wrong, as pointed out by Kirill Kobelev in your question's comments section. Now, let's fix that and also add another operator=:
template <typename T>
class Property
{
public:
Property & operator=( const T & src )
{
m_data = src;
return *this;
}
// This one must be specialized
Property & operator=( const QVariant & src );
const T & operator() const
{
return m_data;
}
private:
T m_data;
};
The specialization is therefore quite simple. Here's ones for QString and int:
template <>
Property<QString> &
Property<QString>::operator=( const QVariant & src )
{
return operator=( src.toString() );
}
template <>
Property<int> &
Property<int>::operator=( const QVariant & src )
{
return operator=( src.toInt() );
}
Now you are free to assign QVariant values directly to any Property which provides that specialization. If you try to do it on a class that did not specialize then you will get an error.
I don't have the reputation to comment, nor the expertise to claim insight so please don't take this as an "answer".
But your question reminded me of a lesson on Cpp, Overloads and Functions over at http://www.cplusplus.com/doc/tutorial/functions2/ .
Excerpt:
"In the example above, we used the function template sum twice. The first time with arguments of type int, and the second one with arguments of type double. The compiler has instantiated and then called each time the appropriate version of the function.
Therefore, result will be a variable of the same type as the parameters a and b, and as the type returned by the function.
In this specific case where the generic type T is used as a parameter for sum, the compiler is even able to deduce the data type automatically without having to explicitly specify it within angle brackets."
Apologies if I missed the point, but thought this may help.

Comparing two objects of the same class

I am trying to overload the == operator in C++.
#include <string>
using namespace std;
namespace date_independent
{
class clock
{
public:
int clockPair[2] = {0,0};
operator string() const
{
string hourString;
string minString;
if(clockPair[0]<10)
{
hourString = "0"+to_string(clockPair[0]);
}
else
{
hourString = to_string(clockPair[0]);
}
if(clockPair[1]<10)
{
minString = "0"+to_string(clockPair[1]);
}
else
{
minString = to_string(clockPair[1]);
}
return hourString+":"+minString;
};
bool operator ==(const clock&clockOne, const clock&clockTwo) const
{
return string(clockOne)==string(clockTwo);
};
};
};
There is much more code than I have included, but this is the important part. I want it so that the == operator can compare two objects of class clock. E.g., object1==object2. Is there anybody that can help me?
A binary operator like == can be overloaded either as a member function with a single parameter (this being the left-hand operand, and the parameter being the right-hand one), or as a non-member function with two parameters for the two operands.
So either
move your operator declaration outside the class declaration (moving the definition to a source file, or declaring it inline if you keep the definition in the header); or
add friend to the definition, so that it declares a non-member in the surrounding namespace; or
remove the first argument from the member function, using this instead.
As a member, it would look like
bool operator==(const const & clockTwo) const {
return string(*this) == string(clockTwo);
}
You might also want to compare the two integer values directly to save the expense of making strings. You should also remove the rogue ; after the function and namespace definitions, although most modern compilers shouldn't object to their presence.
Your comparison function has been written to take two clock objects and compare them, so it should be a non-member function (after the class definition), without the const qualifier.
bool operator==(const clock& clockOne, const clock& clockTwo)
{
return string(clockOne) == string(clockTwo);
}
When you have an operator inside the class definition, the left-hand argument is implicitly provided for you (it's *this), so if you wanted to implement it there you'd need something like:
bool operator==(const clock& clockTwo) const
{
return string(*this) == string(clockTwo);
}
Still, that's not recommended for == as if you have say an implicit constructor from another type T, you won't be able to write code ala my_t == my_clock with the member version unless T provides a suitable comparison operator (for clock or string). A non-member operator gives more symmetric operation.
Overloading can be done inside or outside the class definition. If you want to do it inside, the function receives only one argument. You should compare this with that argument.
bool operator ==(const clock&clockTwo) const
{
return string(*this)==string(clockTwo);
}
Note the const after the argument, it means that you won't change this inside the function.
On the other hand, if you want to do it outside the class definition, it needs two arguments, and you should compare them.
bool operator ==(const clock&clockOne, const clock&clockTwo)
{
return string(clockOne)==string(clockTwo);
}
Also note that it'll be faster to compare the clockPair of the objects rather than making the string and comparing them.
Though your question is poorly worded I believe that you are asking why the operator you've defined is not working?
If you are defining the operator as a member of the class it only takes one parameter. For example:
class clock {
bool operator ==(const clock& rhsClock) const
{
// Note: this is the lhsClock
return string(*this) == string(otherClock);
}
};
When you define the operator as a free function (not as a part of the class) then you need to define both parameters:
class clock {
// ... class declaration ...
};
bool operator ==(const clock& lhsClock, const clock& rhsClock)
{
return string(lhsClock) == string(rhsClock)
}
Where the comparison would look like this:
if (lhsClock == rhsClock) // ... do something ...

C++ overloading operator<<

I'm trying to overload the << operator for a class to emulate toString() in Java. I have a NumExpr class, and has private variable number that I want to output. so here they are:
NumExpr::NumExpr( string n ) {
number = atoi( n.c_str() );
}
string NumExpr::name() {
return "num";
}
ostream & operator<<(ostream &s, const NumExpr &num) {
s << num.number;
return s;
}
I made it a friend function so it can access the private variable
class NumExpr : public Expr {
public:
NumExpr( string v );
string name();
private:
int number;
friend ostream& operator<<(ostream &s, const NumExpr &num);
};
However I'm getting this error
./ast/Expr.cpp: In function ?std::ostream& operator<<(std::ostream&, const NumExpr&)?:
./ast/Expr.cpp:50: error: no match for ?operator<NumExpr::number?
./ast/Expr.cpp:49: note: candidates are: std::ostream& operator<<(std::ostream&, const NumExpr&)
I have searched for this error, people seem to be having the same problems but mine seems to look like the solutions people are giving out. Is there something fundamentally wrong that I'm doing or is there some syntax shenanigans that I'm not aware of?
Thanks for the help!
Okay here it is, little bit of playing around I can reproduce your problem:
The problem is that You forgot to include iostream header file.
Add:
#include<iostream>
and it should just work fine :)
EDIT:
As #James Kanze correctly suggests in comments, it is sufficient to include
#include<istream>
because you don't need everything from the iostream really.
The downside of including iostream inside of istream is little increase in compilation time.
On this page:
http://www.cplusplus.com/forum/beginner/13164/
It says to have the friend function like this:
friend std::ostream& operator<< (std::ostream&, const NumExpr&); <-
so no variable decleration. just
const NumExpr
any help?

Unable match function definition to an existing definition in templated class

I'm sorry if such a question is asked before but i could not find no matter how much I searched (there were similar questions but none of them seemed to work for me).
I am writing a templated class and everything works fine except when I try to overload operator+. I try to overload operator+ two times for different parameters but compiler does not see one of the definitions and gives an eror. Here's the code:
Worker.h (one of my previos homeworks, implemented the problem here since it is easier to see ):
#ifndef _WORKER_H
#define _WORKER_H
#include <string>
#include "Project.h"
using namespace std;
template <class T>
class Worker {
public:
Worker(const string &, Project &);
void Work(const int &);
const Worker & Worker::operator+(const int &); //Problem
const Worker & Worker::operator+(const string &); //Problem
string getName() const;
int getTime() const;
private:
string myName; //The name of the worker
Project & myProject;
int myTime; //Variable to keep track of how much the worker worked.
};
#include "Worker.cpp"
#endif
and the relevant part of Worker.cpp:
template <class T>
const Worker<T> & Worker<T>::operator+(const int & add)
{
cout << add;
return *this;
}
template <class T>
const Worker<T> & Worker<T>::operator+(const string & add)
{
cout << add;
return *this;
}
+ operators are not doing anything right now, the problem is the compiler only sees first declared function (in this case the with the parameter int). There also does not seem to be problem with the functions because if I try to overload only one time, both of them work fine alone. Also I can use them (making the necessary changes) in a non-templated class.
I think it is something simple but since I'm new to templates I could not figure out what the problem was.
There are a few problems with your approach, unrelated to templates.
First your operators would only work for one ordering of operations: Worker<T> + int, and not int + Worker<T>
Second typically you would want to return a new Worker instance, not return this by reference, because A+Bshould not modify A or B.
So what you could do is define non-member operators for the different orderings:
template <typename T>
Worker<T> operator+(int i, const Worker<T>& t) { }
template <typename T>
Worker<T> operator+(const Worker<T>& t, int i) { }
and so on.
Note that for operators that should affect the state of the object, such as +=, *= and so on, the usual approach is to use member operators and return by reference, because in these cases it makes perfect sense.
2 things here, 1 of which is your issue
The return type of a member function is not affected by the fact that the class is a template, hence the declaration of operator+ returning Worker and the definition returning Worker<T> are different. In the class definition, they should be:
const Worker<T> & operator+(const int &); //Problem
const Worker<T> & operator+(const string &); //Problem
The other thing which is also changed in the above code is you don't need the scope (Worker::) in a class declaration

c++ error : (private data member) was not declared in this scope

Say I have a class like so:
class Ingredient
{
public:
friend istream& operator>>(istream& in, Ingredient& target);
friend ostream& operator<<(ostream& out, Ingredient& data);
private:
Measure myMeas;
MyString myIng;
};
In this overloaded friend function, I'm trying to set the value of myIng
istream& operator>>(istream& in, Ingredient& target)
{
myIng = MyString("hello");
}
In my mind, this should work because I'm setting the value of a private data member of the class Ingredient in a friend function and the friend function should have access to all the private data members right?
But I get this error: ‘myIng’ was not declared in this scope
Any idea on why this is happening?
Because you need to be be explicit that you are accessing a member of the target parameter, not a local or global variable:
istream& operator>>(istream& in, Ingredient& target)
{
target.myIng = MyString("hello"); // accessing a member of target!
return in; // to allow chaining
}
The above will work exactly because the operator is a friend of Ingredient as you mention. Try removing the friendship and you will see that accessing private members will no longer be possible.
Also, as Joe comments: stream operators should return their stream parameter so that you can chain them.
In that scope, there is nothing called myIng. The error is pretty clear on that. Its Ingredient& target who has a myIng member, so you should write:
target.myIng = MyString("hello");