当我执行以下操作时:
template <typename T>
class Container
{
public:
class Iterator
{
friend bool operator==(const Iterator& x, const Iterator& y);
};
};
gcc给了我以下警告和建议:
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)
我很确定这是一个新警告,因为我一直这样做,从来没有遇到过任何问题。
有人可以解释为什么这是一个警告,它警告什么?
答案 0 :(得分:6)
它警告说,实际上不可能在课外定义operator==
。
也就是说,friend
声明与非模板operator==
函数成为朋友 - 例如,Container<Int>::Iterator
具有作为朋友的函数
bool operator==(const Container<Int>::Iterator&, const Container<Int>::Iterator&);
此函数不是模板,因此几乎无法为类模板定义之外的所有可能operator==
定义Container
。< / p>
如果您尝试
template<class T>
bool operator==(const Container<T>::Iterator&, const Container<T>::Iterator&);
这是一个功能模板,与朋友声明不匹配。 (在这种情况下,它更糟糕,因为你可以实际使用此运算符,因为T
处于非推导的上下文中。)
警告消息提示了一种可能的解决方法 - 首先声明一个函数模板,然后与它进行特化。 (您需要将Iterator
从类中拉出到自己独立的类模板中,以便可以推导出T
。)另一种可能的解决方法是在类模板中定义函数定义
答案 1 :(得分:4)
声明
friend bool operator==(const Iterator& x, const Iterator& y);
在最近的封闭命名空间范围内声明非模板函数,该范围采用类型为const typename Container<T>::Iterator&
的两个参数。因此,每次实例化类Container
时,使用一些模板参数T
,都会声明operator==
的新重载。
由于此operator==
未从模板实例化,因此您无法将其定义为模板外的。因此,定义此声明的operator==
的唯一方法是为实例化Container
的每种类型单独定义它。这几乎肯定是不可取的。
警告警告您,您声明的朋友不是模板,这会产生我刚才解释过的不良后果。
我相信你正在尝试做的事情的正确方法如下:
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==
现在我们显式地将operator==
声明为模板,并且迭代器的每个特化都声明operator==
作为其朋友的相应特化。