Pregunta

Estoy trabajando en dos clases de contenedor que definen tipos de datos reales y complejos. Cada clase define constructores sobrecargados, así como los cuatro operadores aritméticos +, -, *, / y cinco operadores de asignación =, + = etc. Para evitar la repetición del código, estaba pensando en usar funciones de plantilla cuando la izquierda y la derecha Los argumentos del lado de un operador son de un tipo de datos diferente:

// 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

  ...
};

El problema aquí es ese código como:

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

devuelve el error del compilador ( gcc ) sobrecarga ambigua para 'operator *' en 'ac * br' , ya que el compilador no puede distinguir entre:

  • template <class T> friend const Complex operator*(const Complex&, const T&) [con T = Real]
  • template <class T> friend const Real operator*(const T&, cont Real&) [con T = Complejo]

¿Hay alguna forma de especificar que T no puede ser un Complejo en la definición del operador de plantilla * en la clase Real? ¿O tengo que prescindir de las plantillas y definir cada operador para cada combinación posible de tipos de datos de argumentos? ¿O hay alguna forma de rediseñar el código?

¿Fue útil?

Solución

Ah, el problema de los operadores ...

¡Boost creó una buena biblioteca para que, al proporcionar un mínimo de lógica, todas las demás variaciones se agreguen automáticamente para usted!

Eche un vistazo a Boost.Operators !

Ahora, para su problema, en realidad, como notó, tendrá que definir ambos tipos de operadores (int y double) en lugar de utilizar una plantilla genérica. Si hay mucha lógica en estos operadores (lo cual dudo), siempre puede hacer que llamen a un método común (con plantilla).

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);
}

Pero si usa Boost.operators solo proporcionará Complex :: operator * = (int) y Complex :: operator * = (double) y las versiones independientes se deducirán automáticamente :)

(1) Puede usar pasar por valor aquí, si todos los argumentos son incorporados. También es posible que desee considerar Boost.CallTraits , que elige automáticamente entre by-value y by-ref dependiendo de si el argumento está incorporado o no. Es útil para plantillas.

(2) Al devolver argumentos por valor, no es sensato calificarlos como const. La palabra clave Complex solo significa algo para referencias y punteros, aquí nada impide que el usuario cree una instancia de '=' ... '¡y usted es afortunado de que no lo haga!

Otros consejos

Puede hacer que la clase Real o Compleja tenga operadores de multiplicación no globales.

class Real 
{
  ........

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

};

¿Puedes hacer explícitos los constructores complejos? Esto significará que la conversión implícita de Real a Complejo no está permitida y debería desambiguar al operador *

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top