C++ error C2801: 'operator =' must be a non-static member - c++

I am trying to overload the operator= in a template class.
I have this template class:
template <class T>
class Matrice
{
T m,n;
public:
template <class V>
friend Matrice<V>& operator=(const Matrice<V> &);
};
template <class T>
Matrice<T>& Matrice<T>::operator=(const Matrice<T> &M)
{
/*...*/
return *this;
}
and I also tried:
template <class T>
class Matrice
{
T m,n;
public:
template <class V>
Matrice<V>& operator=(Matrice<V> &);
};
template <class T>
Matrice<T>& operator=(Matrice<T> &M)
{
/*...*/
return *this;
}
but I still get this error:
error C2801: 'operator =' must be a non-static member

error C2801: 'operator =' must be a non-static member
The bolded word is key here. friend is not a member; it's a friend. Remove that friend keyword and treat operator= as member:
The syntactically proper version is:
template <class T>
class Matrice
{
T m,n;
public:
template <class V>
Matrice<V>& operator=(const Matrice<V> &);
};
template <class T>
template <class V>
Matrice<V>& Matrice<T>::operator=(const Matrice<V> &M)
{
/*...*/
return *this;
}
Although I think that it's wrong to use that template <class V> there; the sematically proper version would be
template <class T>
class Matrice
{
T m,n;
public:
Matrice<T>& operator=(const Matrice<T> &);
};
template <class T>
Matrice<T>& Matrice<T>::operator=(const Matrice<T> &M)
{
/*...*/
return *this;
}
Explanation: you don't generally want to assign Type<V> to Type<T> in this way; if you have to, then it is probably sign of bad design.

The standard says
12.8 Copying and moving class objects [class.copy]
...
17 A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&.
A friend function doesn't fulfill these requirements. It must be a member function.
To address the comments that this is just "plain" assignment, not copy assignment, let's add another quote from the standard:
13.5.3 Assignment [over.ass]
An assignment operator shall be implemented by a non-static member function with exactly one parameter.
In standardese, "shall" doesn't leave any options to do anything else.

You mixed friend and member declarations and definitions: in the first example you declared operator= as a friend but defined it as a class member. In the second example, you declared operator= as a member but tried to define it as a non-member. Your operator= has to be a member (see this question why) and you can do the following:
template <class T>
class Matrice
{
T m,n;
public:
Matrice<T>& operator=(Matrice<T> &);
};
template <class T>
Matrice<T>& Matrice<T>::operator=(Matrice<T> &M)
{
/*...*/
return *this;
}

Related

Template class and Friend template function

C++ Primer: Template and Functioins
template <typename>
class BlobPtr;
template <typename>
class Blob;
template <typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template <typename T>
class Blob
{
friend class BlobPtr<T>;
friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
};
Then:
Blob<char> ca;
Blob<int> ia;
The members of BlobPtr<char> may access the nonpublic parts of ca (or any
other Blob object), but ca has no special access to ia (or any other
Blob) or to any other instantiation of Blob.
Question:
I'd like to test the code. How can I access the nonpublic parts of ia with ca? To clarify, I know it's not possible, but I'd like to test the code to see the error.
You can just add template before using friend.
template<typename T>
class Blob
{
template<typename T1>
friend class Blob;
public:
template<typename T1>
bool operator==(const Blob<T1>& other)
{
return i == other.i;
}
private:
T i;
};
Blob<int> i;
Blob<char> j;
int main()
{
i == j;
}
Adding template makes every Blob<T> class into a friend class of each other. So, every member function of Blob<int> can access to private members of Blob<char> and vice versa.

Force instantiation of friend functions

Assume we have a template class with friend function:
template<class T>
class A {
friend A operator+ (int, const A&);
};
This function is implemented somewhere below:
template<class T>
A<T> operator+ (int i, const A<T>& a) {
...
}
And also there is force instantiation of class template further below:
template class A<int>;
Does this imply that operator+(int, A<int>) will be compiled? Or do I have to force instantiate it separately to achieve that?
Template parameters aren't automatically forwarded to friend declarations. You need to specify a template parameter for the function as well:
template<class T>
class A {
template<class U>
friend A<U> operator+ (int, const A<U>&);
};
Implementation is almost correct, should be
template<class T>
A<T> operator+ (int i, const A<T>& a) {
// ^^^
// ...
}

Non-member operator overloading of inner class templates

I prefer to write definitions for class and function templates in a separate file which is automatically included after the "public" header. However, I've come to an interesting case where it looks like I can't do that.
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
int main()
{
Type a;
Type b;
a == b;
}
Is it possible to write definition of operator== separately that will work for any T and U?
For a particular specialization, yes:
template <typename T>
class Outer
{
public:
template <typename U>
class Inner
{
int x = 42;
friend bool operator ==(const Inner& lhs, const Inner& rhs);
};
};
using Type = Outer<int>::Inner<short>;
bool operator ==(const Type& lhs, const Type& rhs) {
return lhs.x == rhs.x;
}
int main()
{
Type a;
Type b;
a == b;
}
In your example, each specialization of the template befriends a non-template function that takes that particular specialization as parameters. You could define this function in-class (and then it will be stamped out every time the template is instantiated), or you could define it out-of-class - but then you would have to define one for every specialization you ever use.
As Igor Tandetnik points out, your example declares a non-template friend function, which you'll have to overload for each template instantiation, which is one reason friend functions are allowed to be defined inline (so they can be generated by the template without having to be templates themselves).
If you want to define the friend function as a template, here is the closest I was able to come up with:
template <typename T>
struct Outer {
template <typename U>
struct Inner;
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & );
template <typename T>
template <typename U>
struct Outer<T>::Inner {
friend bool operator==<T,U>(Inner const &, Inner const &);
};
template<typename T, typename U>
bool operator==( typename Outer<T>::template Inner<U> const &, typename Outer<T>::template Inner<U> const & ) {
return true;
}
// I switched this out, because my gcc-4.6 doesn't
// understand "using" aliases like this yet:
typedef Outer<int>::Inner<short> Type;
int main() {
Type a;
Type b;
operator==<int,short>( a, b );
}
Unfortunately, you'll notice the call site of this operator function is very awkward: operator==<int,short>( a, b ). I believe defining a function template on a nested class template like this disables (or at least interferes with) argument deduction, so you have to specify the template parameters explicitly (which means calling it as a function rather than in operator form). This is why the inline friend definition is so convenient. If you really want to define your operator=='s code separately, I'd recommend defining the friend inline to call another function template (with the proper template arguments), which you can then define out-of-line as a free function.

Overload output stream operator of a template class outside of the template

I want to overload the output stream operator << outside the template class definition.
Implementing it inside the template class is ok:
template
<typename T,int _MaxSize=10,template <class C> class Policy=NoCheck,typename Container=std::vector<T>>
class MyContainer : public Policy<T>
{
public:
MyContainer():p(_MaxSize){};
std::ostream& operator<<(MyContainer<T,_MaxSize,Policy,Container>& obj){ };
private:
Container p;
};
But when I tried to do it outside the template class:
template
<typename T,int _MaxSize=10,template <class C> class Policy=NoCheck,typename Container=std::vector<T>>
class MyContainer : public Policy<T>
{
public:
MyContainer():p(_MaxSize){};
friend std::ostream& operator<<(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj);
private:
Container p;
};
template
<typename T,int _MaxSize,template <class C> class Policy,typename Container>
std::ostream& operator<<(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj)
{
};
Compiler complains:
warning: friend declaration ‘std::ostream& operator<<(std::ostream&, MyContainer<T, _MaxSize, Policy, Container>)’ declares a non-template function [-Wnon-template-friend]
tempstruct.cc:39:97: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Can anybody give a simple example on how can the output stream operator << defined outside a template class?
In the related posts that I found here everyone do it inside the template class.
Can anybody give a simple example on how can the output stream operator << defined outside a template class?
No, because it's not simple. I can give a complicated example:
// Declare the class template, because we need it to declare the operator
template <typename,int,template <class C> class,typename> class MyContainer;
// Declare the operator, because (as the error says) templates must be declared
// in the namespace before you can declare them friends. At this point, we can't
// define the operator, since the class template is incomplete.
template
<typename T,int _MaxSize,template <class C> class Policy,typename Container>
std::ostream& operator<<(std::ostream&,MyContainer<T,_MaxSize,Policy,Container>);
// Define the class template
template
<typename T,int _MaxSize=10,template <class C> class Policy=NoCheck,typename Container=std::vector<T>>
class MyContainer : public Policy<T>
{
public:
MyContainer():p(_MaxSize){};
// Include <> to indicate that this is the template
friend std::ostream& operator<< <>(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj);
private:
Container p;
};
// Finally define the operator
template
<typename T,int _MaxSize,template <class C> class Policy,typename Container>
std::ostream& operator<<(std::ostream& out,MyContainer<T,_MaxSize,Policy,Container> obj)
{
// print some stuff
};
In the related posts that I found here everyone do it inside the template class.
I'd do that; it would be much simpler. Or, better still, I'd implement output in terms of the public interface, assuming it gives sufficient access to the container's contents. Then you wouldn't need the friend declaration, so wouldn't need the forward declarations either.

How to declare operator<< for internal class

//cannot declare operator<<(...) here:
//forward declarations:
class External;
template<class T, class Y>
class External::Internal;
template<class T, class Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T,Y>&);
class External
{
template<class T, class Y>
class Internal
{};
Internal data_;
void print() {
/*out is a std::ostream*/
out << data_;
}
};
template<class T, class Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T,Y>&)
{ }
I do want to implement operator<< for Internal but there is a problem when I try to use this operator call from External: It doesn't see this operator when this operator is declared under the definition of this class, and there seems to be no way of declaring this operator above this class definition.
If you're asking how to define Internal<>::operator<< as a friend, then:
class External
{
template<class T, class Y>
class Internal
{
friend std::ostream& operator <<(std::ostream& out, const Internal&)
{
// impl
return out;
}
};
Internal<Foo, Bar> data_;
public:
void print() const
{
/*out is a std::ostream*/
out << data_;
}
};
Armen's answer would work for the << operator itself.
However, your member declaration
Internal data_;
is also incorrect, in the same way. I.e., lacking template arguments for Internal. So in addition to fixing your operator implementation, fix also your member declaration.
Finally, remember that in C++ you can't use something unless it has already been declared. Your usage of << in the inline implementation of print violates that. So you'd better rearrange things (or just declare them) so that anything that's used, is already declared.
Cheers & hth.,
The point is in using forward declarations:
// you promise there will be implementation of this stuff later on:
template<typename T, typename Y>
class External::Internal<T, Y>;
template<typename T, typename Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T, Y>&);
// now declare your class and operator<< function as normal
class External
{
template<class T, class Y>
class Internal
{
};
Internal<Foo, Bar> data_;
void print()
{
// here you can use operator<< with Internal
out << data_;
}
};
template<class T, class Y>
std::ostream& operator<<(std::ostream& out,const External::Internal<T, Y>&)
{
}
template<class T, class Y>
std::ostream& operator<<(std::ostream& out,const External::Internal<T, Y>&)
^^^^^^^^^^ ^^^^^^
{
}
And make sure to declare this function a friend, because Internal is private in External
Update:
here's how you declare a friend. In your class definition write:
template<class T, class Y>
friend std::ostream& operator <<(std::ostream& out, const External::Internal<T,Y>&)
Since a friend-declaration is a declaration, this will solve your forward-declaration issue.
Update: To solve the circular dependency:
First forward-declare internal
template<class T, class Y>
class Internal;
then declare the friend.
Then the rest of your class, it should work.
template<class T, class Y>
std::ostream& operator<<(std::ostream& out, const External::Internal<T, Y>&)
{
}
The External:: behaves as a namespace and is required because operator<< definition is outside of class External.
there is a problem when I try to use this operator call from External
Don't write procedural code inside your class definition. Only declarations.
Write, in order:
Class definition [in header]
operator<< [in header]
Code that uses these things [in source file]