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

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

当我执行以下操作时:

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== 超出 class。

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

作为朋友
bool operator==(const Container<Int>::Iterator&, const Container<Int>::Iterator&);

此函数不是模板,因此几乎没有办法为 [=35= 之外的所有可能的 Container 定义 operator== ] 模板定义。

如果你尝试做

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

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

警告消息提出了一种可能的修复方法 - 首先声明一个函数模板,然后将其特化为好友。 (您需要将 Iterator 从 class 中拉出到它自己单独的 class 模板中,以便可以推导出 T。)另一个可能的解决方法是定义class 模板定义中的函数。

宣言

friend bool operator==(const Iterator& x, const Iterator& y);

在最近的封闭命名空间范围内声明一个 非模板 函数,该函数接受两个 const typename Container<T>::Iterator& 类型的参数。因此,每次实例化 class Container 时,都会使用一些模板参数 T,声明一个新的 overload of 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==的相应特化声明为其友元。