【问题标题】:Overloading Operator-- cannot convert object to base type in assignment重载运算符 - 无法在赋值中将对象转换为基类型
【发布时间】:2019-01-23 06:03:51
【问题描述】:

我正在研究复数的实现。类Complex 有两个私有成员real_partimaginary_part。我想重写乘法运算如下:

  template<typename T, typename D>
  friend Complex operator * (T lhs, D rhs)
  {
    double real_a;
    double real_b;
    double imaginary_a;
    double imaginary_b;

    if(std::is_same<T, Complex>::value)//if lhs is a Complex
      {
        real_a = lhs.real_part;
        imaginary_a = lhs.imaginary_part;
      }
    else //base type, some sort of number
      {
        real_a = lhs;
        imaginary_a = 0;
      }
    if(std::is_same<D, Complex>::value)//if rhs is a Complex
      {
        real_b = rhs.real_part;
        imaginary_b = rhs.imaginary_part;
      }
    else //base type, some sort of number
      {
        real_b = rhs;
        imaginary_b = 0;
      }
    Complex result;
    result.real_part = (real_b*real_a- imaginary_b*imaginary_a);
    result.imaginary_part = (real_b*imaginary_a + imaginary_b*real_a);
    return result;
  }

我的构造函数看起来像:

Complex::Complex()
{
  real_part = 0.0;
  imaginary_part = 0.0;
}

和:

  Complex(T real, T imaginary)
  {
    real_part = real;
    imaginary_part = imaginary;
  }

当我尝试将两个 Complex 相乘时:

  Complex a(4.0, 8.0);
  Complex b(8, 16);
  auto prod = a*b;
  auto prod2 = a * 2;

我收到以下错误:

   In file included from main.cpp:2:
complex.hpp: In instantiation of ‘Complex operator*(T, D) [with T = Complex; D = Complex]’:
main.cpp:13:17:   required from here
complex.hpp:43:16: error: cannot convert ‘Complex’ to ‘double’ in assignment
         real_a = lhs;
         ~~~~~~~^~~~~
complex.hpp:53:16: error: cannot convert ‘Complex’ to ‘double’ in assignment
         real_b = rhs;
         ~~~~~~~^~~~~
complex.hpp: In instantiation of ‘Complex operator*(T, D) [with T = Complex; D = int]’:
main.cpp:14:20:   required from here
complex.hpp:43:16: error: cannot convert ‘Complex’ to ‘double’ in assignment
         real_a = lhs;
         ~~~~~~~^~~~~
complex.hpp:48:22: error: request for member ‘real_part’ in ‘rhs’, which is of non-class type ‘int’
         real_b = rhs.real_part;
                  ~~~~^~~~~~~~~
complex.hpp:49:27: error: request for member ‘imaginary_part’ in ‘rhs’, which is of non-class type ‘int’
         imaginary_b = rhs.imaginary_part;
                       ~~~~^~~~~~~~~~~~~~

我正在尝试以这种方式重载运算符(使用两种泛型类型)以避免有多个重载乘法运算符(即 LHS 是泛型而 RHS 是复杂类型,反之亦然等)。感谢任何帮助,因为我不确定自己做错了什么。

【问题讨论】:

  • 也添加您的 Complex 构造函数。你使用的是 C++ 的版本?
  • 嗨@P.W,我已经添加了构造函数。我正在使用 C++11。我意识到我的例子有点欠缺;我希望能够将两个 Complexs 相乘以及例如一个int 和一个Complex
  • 我询问版本是因为在 C++17 中,您可以使用 constexpr 来消除不正确的分支。在 C++11 中,您必须使用专业化。我想发布一个答案,但有人打败了我。 :)

标签: c++ templates operator-overloading


【解决方案1】:

我同意Michael Veksler's answer,基本规则是模板函数将根据您调用函数的方式编译为多个实例。当std::is_same 的断言在运行时时,将对所有代码进行编译。因此,编译不会通过,因为您的代码的某些分支对于特定参数类型无效(例如,real_b = rhs.real_part 语句的 int)。

为了简化代码,我们可以为Complex 类型定义另一个构造函数,首先将简单的数字类型(例如intdouble)转换为Complex 类型。

template<typename T>
Complex(T real, T imaginary = 0)
{
    real_part = real;
    imaginary_part = imaginary;
}

那么我们可以修改*运算符重载函数为

static Complex operator * (const Complex & lhs, const Complex & rhs)
{
    Complex result(lhs.real_part*rhs.real_part - lhs.imaginary_part * rhs.imaginary_part,
        lhs.real_part*rhs.imaginary_part + lhs.imaginary_part * rhs.real_part);
    return result;
}

注意:输入参数将由新定义的构造函数或复制构造函数自动转换为Complex 类型。另外,返回的result 是用新的构造函数构造的。

【讨论】:

    【解决方案2】:

    这是因为if 的两个分支都是为同一个实例编译的。其中一些实例是无效的。

    如果您可以使用 c++17,那么您可以将 if 替换为 if constexr,这样只会实例化正确的分支:

    if constexpr (std::is_same<T, Complex>::value)//if lhs is a Complex
      {
        real_a = lhs.real_part;
        imaginary_a = lhs.imaginary_part;
      }
    else //base type, some sort of number
      {
        real_a = lhs;
        imaginary_a = 0;
      }
    if constexpr (std::is_same<D, Complex>::value)//if rhs is a Complex
      {
        real_b = rhs.real_part;
        imaginary_b = rhs.imaginary_part;
      }
    else //base type, some sort of number
      {
        real_b = rhs;
        imaginary_b = 0;
      }
    

    对于严格的C++11,可以使用函数重载来区分这两种类型:

      template<typename T>
      static  T  getReal(T x)
      {
          return x;
      }
      static  double  getReal(Complex x)
      {
          return x.real_part;
      }
      template<typename T>
      static  T  getImaginary(T x)
      {
          return 0;
      }
      static  double  getImaginary(Complex x)
      {
          return x.imaginary_part;
      }
    
      template<typename T, typename D>
      friend Complex operator * (T lhs, D rhs)
      {
        double real_a = getReal(lhs);
        double real_b = getReal(rhs);
        double imaginary_a = getImaginary(lhs);
        double imaginary_b = getImaginary(rhs);
    
        Complex result;
        result.real_part = (real_b*real_a- imaginary_b*imaginary_a);
        result.imaginary_part = (real_b*imaginary_a + imaginary_b*real_a);
        return result;
      }
    

    【讨论】:

      【解决方案3】:

      模板的实例化必须对其整体进行类型检查。

      虽然您可以在编译时使用if constexpr 来选择一个分支,但我认为这实际上是更简单的老式方法,具有重载且没有条件:

      // Mutating multiplication as a member
      template<typename T>
      Complex<T>& Complex<T>::operator*=(const Complex<T>& rhs)
      {
          auto real = real_part;
          auto imaginary = imaginary_part;
          real_part = real * rhs.real_part - imaginary * rhs.imaginary_part;
          imaginary_part = imaginary * rhs.real_part + real * rhs.imaginary_part;
          return *this;
      }
      
      // These are free non-friend functions.
      template<typename T>
      Complex<T> operator*(Complex<T> lhs, const Complex<T>& rhs)
      {
          return lhs *= rhs;
      }
      
      template<typename T>
      Complex<T> operator*(const Complex<T>& lhs, T rhs)
      {
          return lhs * Complex(rhs, 0);
      }
      
      template<typename T>
      Complex<T> operator*(T lhs, const Complex<T>& rhs)
      {
          return rhs * lhs;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-03
        • 1970-01-01
        • 2011-05-02
        • 1970-01-01
        • 2015-06-02
        • 1970-01-01
        • 2021-07-05
        相关资源
        最近更新 更多