Оператор перегрузки - не может преобразовать объект в базовый тип в присваивании - PullRequest
0 голосов
/ 23 января 2019

Я работаю над реализацией комплексных чисел. Класс Complex имеет двух закрытых членов: real_part и imaginary_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 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 голосов
/ 23 января 2019

Инстанциация шаблона должна полностью проверяться типами.

Хотя вы можете использовать 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;
}
0 голосов
/ 23 января 2019

Я согласен с Ответом Майкла Векслера , , т. Е. , основное правило заключается в том, что функции шаблона будут компилироваться в несколько экземпляров в соответствии с тем, как вы вызывали функцию. Тем не менее, компиляция будет выполнена для всего кода, так как утверждение std::is_same находится во время выполнения. Следовательно, компиляция не пройдет, так как некоторые ветви вашего кода недопустимы для определенных типов аргументов (например, int для операции rhs.real_part).

Чтобы упростить код, мы можем определить другой конструктор для типа Complex, чтобы сначала привести другие числовые типы ( например, , int или double) к типу 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 создается с новым конструктором.

0 голосов
/ 23 января 2019

Это потому, что обе ветви 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;
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...