When I do the following:
template <typename T>
class Container
{
public:
class Iterator
{
friend bool operator==(const Iterator& x, const Iterator& y);
};
};
gcc gives me the following warning and suggestion:
warning: friend declaration
'bool operator==(const Container<T>::Iterator&,
const Container<T>::Iterator&)'
declares a non-template function [-Wnon-template-friend]
friend bool operator==(const Iterator& x, const Iterator& y);
^
(if this is not what you intended,
make sure the function template has already been declared
and add <> after the function name here)
I am fairly sure that this is a new warning, since I have always done it like this and never had any problems.
Can someone please explain why is this a warning, and what it warns about?
It's warning about the fact that it is going to be virtually impossible to define that operator==
out-of-class.
That is to say, that friend
declaration befriends a non-template operator==
function - for example, Container<Int>::Iterator
has as a friend the function
bool operator==(const Container<Int>::Iterator&, const Container<Int>::Iterator&);
This function is not a template, so there's pretty much no way to define operator==
for all possible Container
s outside the class template definition.
If you try to do
template<class T>
bool operator==(const Container<T>::Iterator&, const Container<T>::Iterator&);
That's a function template, and doesn't match the friend declaration. (In this case it's even worse, as you can't actually use this operator because T
is in a non-deduced context.)
The warning message suggests one possible fix - first declaring a function template and then befriending a specialization of it. (You'll need to pull Iterator
out of the class into its own separate class template so that T
can be deduced.) The other possible fix is to just define the function inside the class template definition.
The declaration
friend bool operator==(const Iterator& x, const Iterator& y);
declares a non-template function at the nearest enclosing namespace scope which takes two arguments of type const typename Container<T>::Iterator&
. Thus, every time the class Container
is instantiated, with some template parameter T
, a new overload of operator==
is declared.
Since this operator==
is not instantiated from a template, you cannot define it out-of-line as a template. So the only way to define this operator==
you have declared is to define it separately for each type for which Container
is instantiated. This is almost certainly not desirable.
The warning warns you that the friend you declared is not a template, which has the undesirable consequences I just explained.
I believe the correct way to do what you are trying to do is the following:
template <typename T>
class Container_Iterator;
template <typename T> bool operator==(const Container_Iterator<T>& x,
const Container_Iterator<T>& y);
template <typename T>
class Container
{
public:
typedef Container_Iterator<T> Iterator;
};
template <typename T>
class Container_Iterator {
friend bool operator==<T>(const Container_Iterator<T>& x,
const Container_Iterator<T>& y);
};
// btw, don't forget to define operator==
Now we explicitly declare operator==
as a template, and each specialization of the iterator declares the corresponding specialization of operator==
as its friend.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With