如何正确声明模板 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==
的相应特化声明为其友元。
当我执行以下操作时:
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==
的相应特化声明为其友元。