Неоднозначная перегрузка операторов шаблонов - PullRequest
2 голосов
/ 27 октября 2009

Я работаю над двумя классами-обертками, которые определяют реальные и сложные типы данных. Каждый класс определяет перегруженные конструкторы, а также четыре арифметических оператора +, -, *, / и пять операторов присваивания =, + = и т. Д. Чтобы избежать повторения кода, я думал об использовании шаблонных функций, когда левый и правый аргументы со стороны оператора имеют другой тип данных:

// 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' , поскольку компилятор не может определить разницу между:

  • template <class T> friend const Complex operator*(const Complex&, const T&) [с T = Real]
  • template <class T> friend const Real operator*(const T&, cont Real&) [с T = сложным]

Есть ли способ указать, что T не может быть Complex в определении оператора шаблона * в классе Real? Или я должен обходиться без шаблонов и определять каждый оператор для каждой возможной комбинации типов данных аргумента? Или есть способ изменить код?

Ответы [ 3 ]

2 голосов
/ 27 октября 2009

Ах, проблема операторов ...

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) Вы можете использовать здесь by-value, если все аргументы являются встроенными. Вы также можете рассмотреть Boost.CallTraits , который автоматически выбирает между побочным значением и побочным значением в зависимости от того, является ли аргумент встроенным или нет. Это удобно для шаблонов.

(2) При возврате аргументов по значению бессмысленно квалифицировать их как const. Ключевое слово const означает только что-то для ссылок и указателей, здесь ничто не мешает пользователю создать «простой» Complex ... и вам повезло, что это не так!

1 голос
/ 27 октября 2009

У класса Real или Complex могут быть неглобальные операторы умножения.

class Real 
{
  ........

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

};
0 голосов
/ 27 октября 2009

Можете ли вы сделать сложные конструкторы явными? Это будет означать, что неявное преобразование из вещественного в сложное недопустимо и должно устранять неоднозначность оператора *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...