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]

然而,当尝试声明友元函数并在之后定义,事情变得更复杂。事实上,我们有两种选择:

  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';       //错误: 元素类型不支持<<操作

脚注


  1. 这是个模板化实体(templated entity),详见12.1节。 ↩︎

posted @ 2020-09-15 00:19  失落孤舟  阅读(140)  评论(0编辑  收藏  举报