如何正确声明模板类的嵌套类的友元

How to properly declare a friend of a nested class of a template class?

本文关键字:友元 嵌套 何正确 声明      更新时间:2023-10-16

>当我执行以下操作时:

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)

我相当确定这是一个新的警告,因为我总是这样做,从来没有遇到任何问题。

有人可以解释为什么这是一个警告,以及它警告什么吗?

警告说,几乎不可能将这种operator==定义为类外的。

也就是说,friend声明与非模板operator==函数交朋友 - 例如,Container<Int>::Iterator将函数作为友元

bool operator==(const Container<Int>::Iterator&, const Container<Int>::Iterator&);

此函数不是模板,因此几乎无法为类模板定义之外的所有可能Container定义operator==

如果你尝试做

template<class T>
bool operator==(const Container<T>::Iterator&, const Container<T>::Iterator&);

这是一个函数模板,与好友声明不匹配。(在这种情况下,情况更糟,因为您实际上无法使用此运算符,因为T处于非推导上下文中。

警告消息建议了一种可能的解决方法 - 首先声明函数模板,然后与它的专用化交朋友。(您需要将Iterator从类中提取到其自己的单独类模板中,以便可以推断出T。另一个可能的解决方法是只在类模板定义中定义函数。

声明

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==的相应专用化声明为其友元。