Overloading operators '=' and '+' - c++

I'm learning how to use templates and how to overload operators. I've managed to overload operator[], but I've encountered a problem with overloading operator+ and operator=. Here is my code:
template <class T>
class A
{
public:
//...
friend A<T>& A<T>::operator+ (A<T>&, const A<T>&);
friend A<T>& A<T>::operator= (A<T>&, const A<T>&);
};
template<class T> A<T>& A<T>::operator+ (A<T>& left, const A<T>& right)
{
//some functions
return left;
}
template<class T> A<T>& A<T>::operator= (A<T>& left, const A<T>& right)
{
//some functions
return left;
}
Whenver I try to compile, I get those errors:
'+': is not a member of 'A<T>'
'=': is not a member of 'A<T>'
'operator =' must be a non-static member
What am I doing wrong?
EDIT:
I've managed to update the code:
template <class T>
class A
{
public:
//...
A<T> operator+ (A<T>);
A<T> operator= (A<T>, const A<T>);
};
template<class T> A<T> A<T>::operator+ (A<T> right)
{
//some functions
return *this;
}
template<class T> A<T> operator= (A<T> right)
{
//some functions
return *this;
}
Looks like operator+ works now fine, but compiler gives this error:
'operator=' must be a non static member
Why is it a static member, and how can I fix it?

For starters assignment operators must be non-static member functions
From the C++ Standard (13.5.3 Assignment )
1 An assignment operator shall be implemented by a non-static member
function with exactly one parameter. Because a copy assignment
operator operator= is implicitly declared for a class if not declared
by the user (12.8), a base class assignment operator is always hidden
by the copy assignment operator of the derived class.
And secondly (11.3 Friends)
1 A friend of a class is a function or class that is given permission
to use the private and protected member names from the class. A class
specifies its friends, if any, by way of friend declarations. Such
declarations give special access rights to the friends, but they do
not make the nominated friends members of the befriending class.
Thus for example this definition
template<class T> A<T>& A<T>::operator+ (A<T>& left, const A<T>& right)
^^^^^
{
//some functions
return left;
}
is incorrect. At least you should remove A<T>:: because the operator is not a member of the class.

An operator that is implemented as a non-static member must accept only 1 input parameter, the right-hand operand. The left-hand operand is the this object that the operator is being called on.
An operator that is implemented as a static member or a non-member must accept 2 input parameter, the left-hand and right-hand operands.
Your operator= is declared as a non-static member with 2 input parameters, which is wrong.
Also, operator+ is meant to return a new object that is a copy of the two input objects added together. Do not return a reference to the object that the operator is being called on. Whereas operator= is meant to return a reference to the object that is being assigned to.
Try this:
template <class T>
class A
{
public:
//...
A<T> operator+(const A<T>&) const;
A<T>& operator=(const A<T>&);
};
template<class T> A<T> A<T>::operator+(const A<T>& right) const
{
A<T> result(*this);
//some functions to add right to result as needed...
return result;
}
template<class T> A<T>& A<T>::operator=(const A<T>& right)
{
// some functions to copy right into this...
return *this;
}

Related

Template class with implicit conversion and operator overload but not inline

Based on the answer in Implicit conversion when overloading operators for template classes I was able to write the following code that works perfectly fine (simplified example):
namespace my_library {
template <typename T>
struct Number {
T n;
inline Number(T n) : n(n) { }
friend Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}
};
}
int main() {
return (int) (4 + my_library::Number<double>(3)).n; // returns 7
}
All I want to do is make it so that operator+ is not inlined within the definition of Number (but stays in the header file) while everything still works the same way - see the expression in the main function. Note that it requires that the integer 4 gets implicitly converted to double and then to Number<double>. I followed a comment linking to Binary operator overloading on a templated class but that solution did not work - the overloaded operator is no longer matched. Is there any way to make this work and have the body of the operator outside the struct definition? (Without complicating the operator interface or adding more overloads - in those cases I'd rather just keep it inlined.)
You can do it like this:
template <typename T>
struct Number {
// ...
template <class U>
friend Number<U> operator+(const Number<U> &a, const Number<U> &b);
};
template <typename U>
Number<U> operator+(const Number<U> &a, const Number<U> &b) {
return Number<U>(a.n + b.n);
}
In this example, operator+ will be a friend of all Number specializations even when the types don't match. This might be a broader friendship than you intended, but is the simplest way to achieve your objective of moving the definition of operator+ outside the definition of Number. Note that when a friend is not defined inline, you lose the benefit of having it as a "hidden friend". (A hidden friend can only be found via argument-dependent lookup, which means that the compiler will typically not have to consider it as a candidate function in most cases where it is not intended to be used.)
If you want each specialization of operator+ to only be a friend of one particular Number specialization where the types match, it is more complicated. You have to forward-declare the operator+ template in order to prevent the friend declaration from declaring a non-template function, and you also have to forward-declare Number so that it can be used in the operator+ forward declaration:
template <typename T> struct Number;
template <typename T>
Number<T> operator+(const Number<T>&, const Number<T>&);
template <typename T>
struct Number {
// ...
friend Number<T> operator+<>(const Number<T>&, const Number<T>&);
};
template <typename T>
Number<T> operator+(const Number<T> &a, const Number<T> &b) {
return Number<T>(a.n + b.n);
}

friend operator in nested class of templated class

I want to add a iterator class type for my vector class,and I declare some compare operator as friend function of iterator class.but it didnt complie correctly,I did forward declaration.
template<class object>class vector;
template<class object>
bool operator<(typename vector<object>::const_iterator& lhs, typename vector<object>::const_iterator& rhs);
template<class object>class vector {
protected:
//some member
public:
class const_iterator {
friend bool operator< <>(const_iterator& lhs, const_iterator& rhs);
friend bool operator> <>(const_iterator& lhs, const_iterator& rhs);
//...
};
};
compiler said no matching overloaded function found,I use vs2019.I guess something wrong with forward declaration.
and another question is,I notice some people use this form when declare friend function inside class.
class myclass{
friend void foo<T>(T t);
//...
}
but when declare a operator as friend it's different
friend bool operator< <>(const myclass& lhs, const myclass& rhs);
I wonder what's the difference between these two.
please help me,thanks a lot.
In your forward declaration
template<class object>
bool operator<(typename vector<object>::const_iterator&,
typename vector<object>::const_iterator&);
const_iterator is in the non-deduced context, i.e. the compiler will not be able to deduce int for object in the following call:
vector<int>::const_iterator c1;
vector<int>::const_iterator c2;
c1 < c2;
I can suggest two solutions.
The simplest one: omit your forward declarations and provide a definition for operator< inside the body of const_iterator:
friend bool operator<(const_iterator& lhs, const_iterator& rhs) {
... return ... ;
}
If you can't define operator< inside const_iterator, use CRTP to turn a non-deduced context into a deduced one:
template<class derived>
struct const_iterator_crtp {};
template<class derived>
bool operator<(const_iterator_crtp<derived>&,
const_iterator_crtp<derived>&);
template<class object>
struct vector {
struct const_iterator : const_iterator_crtp<const_iterator> {
using base = const_iterator_crtp<const_iterator>;
friend bool operator< <>(base&, base&);
private:
int priv;
};
};
template<class derived>
bool operator<(const_iterator_crtp<derived>& lhs,
const_iterator_crtp<derived>& rhs)
{
auto& l = static_cast<derived&>(lhs); // these static_cast's are safe
auto& r = static_cast<derived&>(rhs);
return l.priv < r.priv;
}
Is the operator< a function template in the first solution? Why we don't need a <> after operator<?
It is not a template. You don't need <> in this definition.
You forward declare a template first. Without <>, a friend declaration introduces a non-template function. A non-template function, even if it has the same name as template one (non-template and template functions can overload!), should be defined somewhere. You'll get a link error without such a definition. To override the default behavior and to refer to the function template that was forward declared earlier, you add <>.

Does the c++ friend keyword mean more then access to private?

I wrote simple class and define one copy constructor.
Then add friend equal comparison operator and compare int with Int
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
friend bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
};
int main() {
int a;
Int<int> x(a);
x == a;
}
Compiled successfully.
If I turn the friend bool operator==(const Int<T>& f, const Int<T>& s); into a non-friend template. I get a compiler error:
error: no match for 'operator==' (operand types are 'int' and 'Int<int>'
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
template <class T>
bool operator==(const Int<T>& f, const Int<T>& s) {
return f.value == s.value;
}
int main() {
int a;
Int<int> x(a);
x == a;
}
Does it mean that friend functions allow specific conversions?
5 == x works too.
Does the c++ friend keyword mean more then access to private?
Depending on context, it can have more implications, yes. For instance, a friend function defined inline, with no other declaration, can only be found by argument dependent lookup, even though it's a member of the enclosing namespace:
namespace foo {
struct bar {
friend void baz(bar const&) {}
};
}
int main() {
foo::bar bar;
// foo::baz(bar); // ill-formed, no member baz in foo
baz(bar); // Okay, it *can* be found by ADL
};
That is not directly related to your question, but that is how the friend operator== is looked up. And that said friend is also not a template itself. When you instantiate Int<int>, this "injects" a free operator== function - which is, again, not a template - into the namespace Int is a member of. When that operator function is looked up (by ADL) for the purposes of doing x == a, the compiler will happily consider implicitly converting a to Int<int>, because we can do implicit conversions to match regular free functions.
And speaking of conversions...
I wrote simple class and define one copy constructor.
You did not. That is a user-defined constructor taking an int const& argument, not an Int<int> const& like a copy constructor would take. You defined a converting constructor (because it's not explicit), which is exactly how the compiler can convert a to Int<int> above.
If I turn...
In your second version the operator is a template. It's still looked up by ADL. But template argument deduction only considers the exact type of the arguments. I.e, both arguments to operator== must be directly able to bind to Int<T> const& for some T. An int cannot be bound directly to Int<int> const&, it requires a conversion. So it doesn't match the sort of argument the template needs to do template argument deduction. Therefore the template cannot be instantiated, and is not a candidate.
Does it mean that friend functions allows specific conversions?
No, it's not the friendship. It's the template vs non-template business. You can define an operator== without friendship, but it has to be per-instantiation of Int:
template <class T>
class Int {
public:
T value;
Int(const T& value_) : value(value_) {
;
}
};
bool operator==(const Int<int>& f, const Int<int>& s) {
return f.value == s.value;
}
That will make your main well-formed too. But as you noticed, it's not very useful having to declare those individually, so many code bases will use the friend version to "inject" this free function automatically.

C++ : friend declaration ‘declares a non-template function

I have a problem to overload the << stream operator and I don't find the solution :
template<class T, unsigned int TN>
class NVector
{
inline friend std::ostream& operator<< (
std::ostream &lhs, const NVector<T, TN> &rhs);
};
template<class T, unsigned int TN>
inline std::ostream& NVector<T, TN>::operator<<(
std::ostream &lhs, const NVector<T, TN> &rhs)
{
/* SOMETHING */
return lhs;
};
It produces the following error message:
warning : friend declaration ‘std::ostream& operator<<(std::ostream&, const NVector&)’ declares a non-template function [-Wnon-template-friend]
error: ‘std::ostream& NVector::operator<<(std::ostream&, const NVector&)’ must take exactly one argument
How to solve that problem ?
Thank you very much.
There are two different issues in your code, the first is that the friend declaration (as the warning clearly says, maybe not so clear to understand) declares a single non-templated function as a friend. That is, when you instantiate the template NVector<int,5> it declares a non-templated function std::ostream& operator<<(std::ostream&,NVector<int,5>) as a friend. Note that this is different from declaring the template function that you provided as a friend.
I would recommend that you define the friend function inside the class definition. You can read more on this in this answer.
template <typename T, unsigned int TN>
class NVector {
friend std::ostream& operator<<( std::ostream& o, NVector const & v ) {
// code goes here
return o;
}
};
Alternatively you can opt for other options:
declare the operator<< template as a friend (will grant access to any and all instantiations of the template),
declare a particular instantiation of that template as a friend (more cumbersome to write) or
avoid friendship altogether providing a public print( std::ostream& ) member function and calling it from a non-friend templated operator<<. I would still opt to befriend the non-template function an provide the definition inside the templated class.
The second issue is that when you want to define an operator outside of the class of the left hand side argument, the operator is a free function (not bound to a class) and thus it should not be qualified:
template<class T, unsigned int TN>
inline std::ostream& operator<<(std::ostream &lhs, const NVector<T, TN> &rhs)
{
/* SOMETHING */
return lhs;
};

"X is not a member of Y" even though X is a friend of Y?

I am trying to write a binary tree. Why does the following code report error C2039, "'<<' : is not a member of 'btree<T>'" even though the << operator has been declared as a friend function in the btree class?
#include<iostream>
using namespace std;
template<class T>
class btree
{
public:
friend ostream& operator<<(ostream &,T);
};
template<class T>
ostream& btree<T>::operator<<(ostream &o,T s)
{
o<<s.i<<'\t'<<s.n;
return o;
}
In
template <typename T>
class BTree
{
// ...
friend std::ostream& operator<<( std::ostream&, T );
// ...
};
you're telling the compiler that there is a non template free function
std::ostream& operator<<( std::ostream&, Type )
for whatever type you happen to instantiate BTree over. But you never
provide such a function. The definition you provide is for a member,
but as a member function, your operator<< takes too many parameters.
Given that BTree is a generic type, it shouldn't provide the means of
displaying its contained elements; that's up to the contained element
type. What would make sense is something like:
template <typename T>
class BTree
{
struct Node
{
// ...
void display( std::ostream& dest, int indent ) const;
};
// ...
void display( std::ostream& dest ) const;
friend std::ostream& operator<<( std::ostream& dest, BTree const& tree )
{
tree.display( dest );
return dest;
}
};
template <typename T>
void BTree::display( std::ostream& dest ) const
{
if ( myRoot == NULL ) {
dest << "empty";
} else {
myRoot->display( dest, 0 );
}
}
template <typename T>
void BTree::Node::display( std::ostream& dest, int indent ) const
{
dest << std::string( indent, ' ' ) << data;
if ( myLeft != NULL ) {
myLeft->display( dest, indent + 2 );
}
if ( myRight != NULL ) {
myRight->display( dest, indent + 2 );
}
}
By declaring the operator friend, you tell the compiler to look for a function
ostream& operator<<(ostream &,T);
where T is the exact same type the btree class template is instantiated with. (e.g. for btree<Node>, the actual signature would be ostream& operator<<(ostream &, Node); -- assuming you hace members i and n of type Node)
This function will have access to private and protected members (variables and functions) of the class btree<T> for all instances of T, but it is not actually a member of the class (as it would be without the friend keyword).
The operator definition you provide is for an operator that is a member of the template class btree, as if you have declared
template<class T>
class btree
{
public:
ostream& operator<<(ostream &,T);
};
This is due to the btree<T>:: prefix you included (that specifies which class the function/operator belongs to).
Since there is no corresponding operator declaration in the class (see the above description of the friend declaration), the compiler complains.
To fix it, you either
keep the friend declaration, remove the btree<T>:: prefix and template<class T> from the operator defintion and change the second parameter type to btree<Type>&, where Type is one of the types you expect the btree template to be instantiated with (e.g. Node) -- then supply similar defintions for other such types as well.
or remove the friend keyword from the declaration in the class and remove the T parameter from both the declaration and the definition as now the operator is supposed to work on the whole btree (which is implicitly supplied via *this).
Alternatively, you can experiment with declaring the friend operator as a template, but that requires some more modifications: (read more about forward declaration)
template<class T> btree; // forward declaration of class btree
// forward declare operator (or move definition here)
template<class T>
ostream& operator<<(ostream &o, btree<T>& s);
// declare operator as template friend
template<class T>
class btree
{
public:
friend ostream& operator<< <> (ostream &, bree<T>&);
// note <> after operator name to denote template with no new template parameters
};
Note that above I assumed that you want to output the whole tree (that is invoke the operator<< on a btree object). It is not clear from the code you have whether this is your intention (class btree does not have members i and n). If not, and the type you want to invoke the << operator on is the actual template parameter of btree, then you don't need to change the second parameter of the templated operator from T, but there is also no need to declare it as friend of class btree as the operator is independent of btree. You do need to declare it as friend of the class whose members i and n you are accessing in the definiton of the operator (e.g Node above), if i and/or n is private in that class. The notion about losing btree<T>:: (or Node::) still applies as the operator does not belong to any class.
Couple more things, assuming you go with the friend declaration:
The type of the second parameter to the operator should be btree<T>& (emphasis on &) as it is more efficient to pass a reference to the btree object than to copy the entire btree (or a shallow copy if you use pointers and go with the default copy-contructor)
the second parameter should also be marked const, as (presumably) you do not want to change the btree object during output. Be aware that in this case you will need to mark certain non-changing methods in btree<T> as const as well to allow it to compile. (See the FAQ on const correctness)
EDIT'd a few times to make it clear and ensure correctness
A friend function is granted the same access to members of a class that members get, but it is not a member.
That's the whole point of the friend keyword, to give this access to non-members.
Since your operator<< doesn't use btree<T>, there's no reason to make it a friend of btree<T>.
So I think you meant
friend ostream& operator<<(ostream &, const mydata&);
inside class mydata.
Replace:
template<class T>
ostream& btree<T>::operator<<(ostream &o,T s)
{
o<<s.i<<'\t'<<s.n;
return o;
}
with:
ostream& operator<<(ostream &o, const mydata &s)
{
o<<s.i<<'\t'<<s.n;
return o;
}
As Ben Voight mentions, the error is telling you that this function is not a member of btree. Also, you seem to be defining that function for mydata exclusively, since it's expecting s and i members.
EDIT
Because it's a friend function, C++ is a bit weird. See, friend functions aren't actually defined in the class, they're defined in a different namespace. You have to provide an output function used by operator<< inside the class definition if you want it to use a templated member function.
The reason I suggest the following method (stream_out) is to demonstrate an easy way to do it in a way that makes it a member and doesn't mislead readers of your code, because it isn't a clever hack.
94% of the time you can use a clever hack such as has been suggested in the comments, but it does not answer the fundamental question: your 'friend' function is not a member of your class unless its body is given in the declaration, period, nothing else to say on the matter.
(What is the other 6% of the time, you ask, that this is not OK? copy constructor nonsense, CLI, and other unspeakable bumps in the night.)
If you absolutely must include it outside, as a member function, you would do something like...
template<class T>
class btree
{
private:
int i;
int n;
void stream_out(std::ostream& o);
public:
friend std::ostream& operator<<(std::ostream& o, btree<T> & me) {
me.stream_out(o);
return o;
}
};
template <class T>
void btree<T>::stream_out(std::ostream& o)
{
o << i << '\t' << n;
}
EDITED to clear up the summary a bit.