C++ Templates (2.4 友元 Friends )
2.4 友元 Friends
除了使用printOn()
方法来打印stack的内容,使用操作<<将是更好的选择。然而,通常操作<<都实现为非成员函数,这可以inline方式调用printOn()
方法:
template <typename T>
class Stack
{
...
void printOn(std::ostream& strm) const { ...}
friend std::ostream& operator<< (std::ostream& strm, Stack<T> const& s)
{
s.printOn(strm);
return strm;
}
};
注意,这意味着类Stack<>
的操作<<不是一个函数模板,而是在有必要时用类模板实例化的一个普通函数[1]。
然而,当尝试声明友元函数并在之后定义,事情变得更复杂。事实上,我们有两种选择:
- 隐式地定义一个新的函数模板,这必须使用一个不同的模板参数,比如U:
template <typename T>
class Stack
{
...
template <typename U>
friend class std::ostream& operator<< (std::ostream&, Stack<U> const&);
};
不管再次使用T还是跳过模板参数声明都无法工作(不管是内层T屏蔽外层T还是在命名空间范围内声明非模板参数)。
2. 前向声明Stack<T>
的输出操作为模板,这然而意味着不得不前向声明Stack<T>
:
template <typename T>
class Stack;
template <typename T>
std::ostream& operator << (std::ostream&, Stack<T> const&);
然后声明该函数为友元:
template <typename T>
class Stack
{
...
friend std::ostream& operator<< <T> (std::ostream&, Stack<T> const&);
};
注意“函数名”即<<操作后面的<T>
。因此,我们声明了一个非成员函数模板的特化版本作为友元。没有<T>
,我们将声明一个新的非模板函数,详见第12.5.2节。
在任何情形下,可以依然使用没有定义<<操作的类作为成员。只用调用该Stack的<<操作才会引发错误:
Stack<std::pair<int, int>> ps; //std::pair<>没有定义<<操作
ps.push({4, 5}); //OK
ps.push({6, 7}); //OK
std::cout << ps.top().first << '\n'; //OK
std::cout << ps.top().second << '\n'; //OK
std::cout << ps << '\n'; //错误: 元素类型不支持<<操作
脚注
这是个模板化实体(templated entity),详见12.1节。 ↩︎