重载运算符-无法在分配中将对象转换为基本类型

时间:2019-01-23 06:03:51

标签: c++ templates operator-overloading

我正在努力实现复数。类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类型,反之亦然,等等)。非常感谢您的帮助,因为我不确定自己在做什么错。

3 个答案:

答案 0 :(得分:1)

这是因为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;
  }

答案 1 :(得分:1)

模板的实例化必须完整地进行类型检查。

虽然您可以在编译时使用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;
}

答案 2 :(得分:1)

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

为简化代码,我们可以为Complex类型定义另一个构造函数,以将其他数字类型( eg 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是使用新的Constructor构造的。