Question

Je travaille sur deux classes de wrapper qui définissent des types de données réels et complexes. Chaque classe définit des constructeurs surchargés, ainsi que les quatre opérateurs arithmétiques +, -, *, / et cinq opérateurs d’assignation =, + = etc. Pour éviter de répéter le code, je pensais utiliser des fonctions de modèle lorsque les symboles gauche et droit Les arguments côté opérateur d'un opérateur sont d'un type de données différent:

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

  ...
};

Le problème ici est que ce code ressemble à:

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

renvoie le compilateur ( gcc ), une surcharge ambiguë pour 'operator *' dans 'ac * br' , le compilateur ne pouvant pas différencier:

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

Existe-t-il un moyen de spécifier que T ne peut pas être un complexe dans la définition de l'opérateur de modèle * de la classe Real? Ou dois-je me passer de modèles et définir chaque opérateur pour chaque combinaison possible de types de données d'argument? Ou existe-t-il un moyen de redéfinir le code?

Était-ce utile?

La solution

Ah, le problème des opérateurs ...

Boost a créé une belle bibliothèque de sorte qu'en fournissant un minimum de logique toutes les autres variantes soient automatiquement ajoutées pour vous!

Jetez un coup d’œil à Boost.Operators !

Maintenant, pour votre problème, comme vous l'avez remarqué, vous devrez définir les deux types d'opérateurs (int et double) plutôt que d'utiliser un modèle générique. S'il y a beaucoup de logique dans ces opérateurs (ce dont je doute, vous pouvez toujours les appeler une méthode commune (basée sur un modèle).

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

Mais si vous utilisez Boost.operators, vous ne fournissez que Complex :: operator * = (int) et Complex :: operator * = (double) et les versions autonomes seront automatiquement déduites:)

(1) Vous pouvez utiliser passer par valeur ici, si tous les arguments sont intégrés. Vous pouvez également envisager de Boost.CallTraits , qui choisit automatiquement entre valeur et valeur par référence selon que l'argument est intégré ou non. C'est pratique pour les modèles.

(2) Lors du renvoi d'arguments par valeur, il est insensé de les qualifier de const. Le mot-clé Complex signifie seulement quelque chose pour les références et les pointeurs, ici rien n'empêche l'utilisateur d'instancier un "simple" <=> ... et vous avez de la chance que ce ne soit pas le cas!

Autres conseils

Vous pouvez faire en sorte que la classe Real ou la classe Complexe ait des opérateurs de multiplication non globaux.

class Real 
{
  ........

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

};

Pouvez-vous rendre explicites les constructeurs complexes? Cela signifiera que la conversion implicite de Real en Complexe n'est pas autorisée et devrait désambiguïser l'opérateur *

.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top