Reputation: 506
I create a template class and want to overload an operator + (several times). I do this in the following way
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
....
template <typename T>
class Polynomial {
....
public:
....
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
friend const Polynomial<T> operator + <> (const Polynomial<T>& poly, const T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
However, I got the following error (which corresponds to the line that begins with 'friend')
problem2.cpp:282:45: error: declaration of ‘operator+’ as non-function
problem2.cpp:282:45: error: expected ‘;’ at end of member declaration
problem2.cpp:282:47: error: expected unqualified-id before ‘<’ token
Following Raxvan's advise, I've changed the code
template class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other);
....
template <typename T>
class Polynomial {
....
public:
....
friend ostream& operator << <> (ostream& out, const Polynomial<T>& other);
Polynomial operator +(const Polynomial& other) const {
// impelementation
}
template <typename NOT_T>
friend const Polynomial<NOT_T> operator +(const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
ostream& operator <<(ostream& out, const Polynomial<T>& other) {
// implementation
}
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
// implementation
}
And in this code I don't have problems with operator << as I had with operator +. Can anyone explain the defference?
Upvotes: 0
Views: 696
Reputation: 153889
The problem is subtle. Your syntax is very close to being correct. I think your friend declaration should be:
friend Polynominal<T> const operator+<T>( ... );
but both VC++ and g++ accept:
friend Polynominal<> const operator+<T>( ... );
when they can see the declaration:
template <typename T>
const Polynomial<T> operator+(const Polynomial<T>& poly, const T& scalar);
(I can't find anything in the standard to justify this off hand, but since both VC++ and g++ do it, I suppose that it's something I've missed.)
And therein lies the problems. The declaration at namespace
scope of operator+
is hidden by the in-class definition. The
compiler complains because the operator+
it finds (the in
class definition) isn't a template itself (although it is
a member of a class template).
If you don't have the problem with operator<<
, it's because
you don't have a member function with the same name.
There are several ways of solving this problem. The simplest is
probably to make all of the operator+
friends. Or not: the
most common approach to this is to implement operator+
in
terms of operator+=
(which should be a member, in all cases).
In which case, operator+
doesn't have to be a friend.
Or you don't make operator+
a template at all, but definite it
inside your class template:
template <typename T>
class Polynomial
{
friend Polynomial operator+( Polynomial const& lhs, Polynomial const& rhs )
{
// ...
}
friend Polynomial operator+( Polynomial const& lhs, T const& rhs )
{
// ...
}
friend Polynomial operator+( T const& lhs, Polynomial const& rhs )
{
// ...
}
}
(Note that the functions being defined are not templates, but
separate overloaded non-template functions, one for each
instantiation of Polynomial
. But the results end up being the
same.)
In this case, you probably would want to have a member function,
called by the operator+
functions, which would do the actual
work; you don't want too much code directly inline like this.
Upvotes: 2
Reputation: 6505
You have to have the same definition when you label a function as friend, this includes the template used above with another type , not T
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
template < class NOT_T> //must respect the deffinition from above
friend const Polynomial<NOT_T> operator + (const Polynomial<NOT_T>& poly, const NOT_T& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar)
{
//...
}
Edit:
For a simplified explanation i have changed the function to foo
and bar
to illustrate the difference in declarations:
template <typename T> class Polynomial;
template <typename T>
void bar(const Polynomial<T>& );
void foo(const Polynomial<float> & );//foo for speciffic float
template <typename T>
class Polynomial {
public:
template <typename> //this is also valid declaration;
friend void bar(const Polynomial<T> & );
//it just has to have template because it's a template functions declaration
//not a valid declaration:
//friend void bar <> (const Polynomial<T> & );
//this declaration has no template;
//it refers to a foo function specific to Polynomial<T> type
//so if you use Polynomial<float> there must be a foo for floats
friend void foo(const Polynomial<T> &);
};
template <class T>
void bar(const Polynomial<T>&)
{
}
void foo(const Polynomial<float> &)
{
}
void main()
{
Polynomial<float> pf;
Polynomial<int> pi;
foo(pi);//error since there is not **foo** declared for int
foo(pf);//ok; we have **foo** for Polynomial<float>
bar(pf);
bar(pi);//both ok since bar is templated function;
}
Raxvan.
Upvotes: 1
Reputation: 33655
Your operator+
is a function template, to make this a friend, you need to declare it fully including the template parameters, however with a different template parameter, for example:
#include <iostream>
template <typename T> class Polynomial;
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar);
template <typename T>
class Polynomial {
public:
Polynomial operator +(const Polynomial& other) const {
std::cout << "inline +" << std::endl;
}
// Here introduce a different type to indicate that this is a template...
template <typename U>
friend const Polynomial<U> operator + (const Polynomial<U>& poly, const U& scalar);
};
template <typename T>
const Polynomial<T> operator +(const Polynomial<T>& poly, const T& scalar) {
std::cout << "friend +" << std::endl;
}
int main(void)
{
Polynomial<int> f;
f = f + 1;
f = f + 1.; // this fails
f = f + Polynomial<int>();
}
Upvotes: 1