【问题标题】:Ambiguous overload on template operators模板运算符的模棱两可的重载
【发布时间】:2010-12-10 10:22:16
【问题描述】:

我正在研究定义真实和复杂数据类型的两个包装类。每个类都定义了重载的构造函数,以及四个算术运算符+、-、*、/和五个赋值运算符=、+=等。为了避免重复代码,我在考虑左右时使用模板函数- 运算符的手边参数属于不同的数据类型:

// real.h
class Real {
public:
  explicit Real(const double& argument) {...}
  explicit Real(int argument) {...}
  ...

  friend const operator*(const Real&; const Real&);
  template <class T> friend const Real operator*(const Real&, const T&);
  template <class T> friend const Real operator*(const T&, cont Real&);
  // Here, T is meant to be a template parameter for double and int

  // Repeat for all other arithmetic and assignment operators
};

// complex.h
class Complex {
public:
  explicit Complex(const Real& realPart) {...}
  explicit Complex(const Real& realPart, const Real& imaginaryPart) {...}
  // Overload for double and int data types
  ...

  friend const operator*(const Complex&, const Complex&);
  template <class T> friend const Complex operator*(const Complex&, const T&);
  template <class T> friend const Complex operator*(const T&, cont Complex&);
  // Here, T is is a template parameter for Real, double and int

  ...
};

这里的问题是这样的代码:

//main.cpp
void main() {
  Complex ac(2.0, 3.0);
  Real br(2.0);
  Complex cc = ac * br;
}

返回编译器 (gcc) 错误'ac * br'中'operator*' 的模糊重载,因为编译器无法区分:

  • template &lt;class T&gt; friend const Complex operator*(const Complex&amp;, const T&amp;) [with T = Real]
  • template &lt;class T&gt; friend const Real operator*(const T&amp;, cont Real&amp;) [with T = Complex]

有没有办法在 Real 类的模板 operator* 定义中指定 T 不能是 Complex?或者我是否必须不使用模板并为每个可能的参数数据类型组合定义每个运算符?或者有没有办法重新设计代码?

【问题讨论】:

    标签: c++ templates operator-overloading


    【解决方案1】:

    啊,运营商的问题……

    Boost 创建了一个不错的库,因此通过提供最少的逻辑,所有其他变体都会自动为您添加!

    看看Boost.Operators

    现在对于您的问题,实际上正如您所注意到的,您必须定义两种类型的运算符(int 和 double),而不是使用通用模板。如果这些运算符中有很多逻辑(我对此表示怀疑),您总是可以让它们调用一个通用(模板化)方法。

    template <typename T>
    Complex complex_mult_impl(T const& lhs, Complex const& rhs) { ... } // Note (1)
    
    // return type is not 'Complex const', see (2)
    Complex operator*(int lhs, Complex const& rhs)
    { 
      return complex_mult_impl(lhs,rhs);
    }
    

    但是如果你使用 Boost.operators 你只提供 Complex::operator*=(int) 和 Complex::operator*=(double) 并且会自动推导出单机版本:)

    (1) 如果所有参数都是内置的,您可以在此处使用按值传递。您可能还需要考虑Boost.CallTraits,它会根据参数是否内置,自动在按值和按引用之间进行选择。它对模板很方便。

    (2) 当按值返回参数时,将它们限定为const 是没有意义的。 const 关键字仅表示引用和指针,这里没有什么可以阻止用户实例化“简单”Complex... 幸运的是它没有!

    【讨论】:

      【解决方案2】:

      您可以使 Real 或 Complex 类具有非全局乘法运算符。

      class Real 
      {
        ........
      
        template <class T> const Real operator*(const T&);
        const Real operator*(const Real&);
      
      };
      

      【讨论】:

        【解决方案3】:

        你能明确复杂的构造函数吗? 这意味着不允许从 Real 到 Complex 的隐式转换,并且应该消除运算符 *

        的歧义

        【讨论】:

        • 构造函数确实应该明确(问题已编辑)。但是,在这种情况下,使它们显式并不能消除编译错误。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-18
        • 1970-01-01
        • 2014-09-26
        相关资源
        最近更新 更多