【问题标题】:C++ friend comparison between two instantiations of one class template一个类模板的两个实例化之间的 C++ 朋友比较
【发布时间】:2010-08-20 04:28:13
【问题描述】:

我正在尝试编写一个类模板,该模板在具有不同模板类型的两个实例之间提供比较运算符。通常情况下,此操作员是非会员朋友。下面是我尝试实现的简化示例。

template<typename T>
class Wrapper {
  // Base type, which must have a val() method to allow comparison
  T t_;
public:
  Wrapper(const T& t) : t_(t) {}

  // Comparison operator
  template<typename B>
  friend
  bool
  operator==(const Wrapper &a, const Wrapper<B>&b) {
    return a.t_.val()==b.t_.val();
  }
};

// First example type for Wrapper
class X {
  int x_;    
public:
  X(int x) : x_(x) {}

  int
  val() const {return x_;}
};

// Second example type for Wrapper
class Y {
  int y_;
public:
  Y(int y) : y_(y) {}

  int
  val() const {return 2*y_;}
};

int
main() {
  Wrapper<X> WX(X(4));
  Wrapper<Y> WY(Y(2));
  return WX==WY ? 1 : 0;
}

此示例 (g++ 4.4.0) 无法编译:相反,它抱怨来自 Wrapper&lt;Y&gt;y_ 是私有的,因此无法访问朋友函数,我明白了原因。但是我该如何解决这个问题?给反转函数添加友谊

  template<typename B>
  friend bool operator==(const Wrapper<B> &, const Wrapper &);

进入 Wrapper 类模板体只会导致编译器产生歧义。我不想让 Wrapper 类的不同实例能够访问彼此的私有成员——我想限制对这个操作符的访问。这可能吗?

我的笔记本电脑因被关闭而处于危险之中,因此我和笔记本电脑(以及与此相关的窗口)都会接受任何想法。

【问题讨论】:

    标签: c++ templates friend


    【解决方案1】:

    事物的数量:

    • 当您的类模板为X 和一次Y 实例化时,您有两个operator== 定义。

    • operator== 移出类声明。

    • 请注意,friend 不是成员。因此,访问冲突相关的诊断。

    试试这个:

    template<typename T>
    class Wrapper {
      // Base type, which must have a val() method to allow comparison
      T t_;
    public:
      Wrapper(const T& t) : t_(t) {}
    
      // Comparison operator
    
      template<typename A, typename B>
      friend bool
      operator==(const Wrapper<A> &a, const Wrapper<B>&b);
    };
    
    template<typename A, typename B>
      bool
      operator==(const Wrapper<A> &a, const Wrapper<B>&b) {
        return a.t_.val()==b.t_.val();
      }
    
    // First example type for Wrapper
    class X {
      int x_;    
    public:
      X(int x) : x_(x) {}
    
      int
      val() const {return x_;}
    };
    
    // Second example type for Wrapper
    class Y {
      int y_;
    public:
      Y(int y) : y_(y) {}
    
      int
      val() const {return 2*y_;}
    };
    
    int
    main() {
      Wrapper<X> WX(X(4));
      Wrapper<Y> WY(Y(2));
      return ::operator==(WX, WY) ? 1 : 0;
    }
    

    虽然我仍然不喜欢有两个可能的friend operator== 潜伏在那里......

    【讨论】:

    • 看起来您得出了与我相同的结论,这对我来说是令人鼓舞的。您对两个可能的 operator== 的怀疑是否有根据?如果是这种情况,编译器不会抱怨一个模棱两可的函数调用吗?
    • 如果你有WX == WY; WY == WX,参数将是相反的顺序。当然,第三种类型(比如“Z”)涉及另一组可能不冲突的op== 定义等等。
    • 为什么说friend operator==有两种可能?编译器将不止一次遇到友元声明,但它们将一个唯一的模板声明为友元,该模板只会被实例化一次。 operator== 的两个参数将是 Wrapper 的每个实例化的朋友,但只有一个这样的模板。我不太记得了,但可能需要在 Wrapper 定义 IIRC 之前转发声明模板。
    • 模板应该根据参数类型(或用作模板参数时的值)的排列来实例化......这本质上没有任何问题,它通常适用于小型函数(微不足道的膨胀) .有问题时有替代方案(例如,转换为单一可比较类型)。
    • @dribeas:这是 w.r.t OP 的代码:X 的模板实例化声明并定义:template&lt;B&gt; bool operator==(const Wrapper&lt;X&gt; &amp;a, const Wrapper&lt;B&gt;&amp;b);Y 的模板实例化:template&lt;B&gt; bool operator==(const Wrapper&lt;Y&gt; &amp;a, const Wrapper&lt;B&gt;&amp;b);。他们不会不一样吗?
    【解决方案2】:

    我的笔记本电脑是安全的(目前),因为重新阅读 C++ FAQ-lite 会有所帮助,尽管该示例最初似乎与我自己的问题不匹配。下面通过将操作符的定义移到模板类主体之外来完成这项工作:

    template <typename T> class Wrapper;
    
    template<typename A, typename B>
    inline
    bool
    operator==(const Wrapper<A> &a, const Wrapper<B>&b) {return a.t_.val()==b.t_.val();}
    
    template<typename T>
    class Wrapper {
      T t_;
    public:
      Wrapper(const T& t) : t_(t) {}
    
      template<typename A, typename B>
      friend
      bool
      operator==(const Wrapper<A> &a, const Wrapper<B>&b);
    };
    

    任何更优雅或有见地的建议将不胜感激。

    【讨论】:

    • 要了解更多信息,请阅读我提供给另一个问题的 answer,但这是模板友谊的问题。
    • @dribeas - 感谢(和 +1)提供链接。非常便利。我希望 SO 允许我们标记最喜欢的答案以及最喜欢的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多