2009-10-27 5 views
2

Je travaille sur deux classes d'emballage qui définissent les types de données réelles 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. Afin d'éviter de répéter le code, je pensais utiliser les fonctions gabarit quand la gauche et la droite arguments -hand-latérales d'un opérateur sont d'un type de données différent:surcharge Ambigu sur les opérateurs de modèle

// 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 le code comme:

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

retourne le compilateur (gcc) erreur de surcharge ambiguë pour 'opérateur *' dans 'ac * br », comme le compilateur ne peut pas faire la différence entre:

  • 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]

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

Répondre

2

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

Boost a créé une belle bibliothèque afin que, en fournissant un minimum de logique toutes les autres variations sont automatiquement ajoutées pour vous!

Jetez un oeil à Boost.Operators!

Maintenant, pour votre problème, en fait comme vous avez remarqué, vous devrez définir les saveurs des 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 faire appeler une méthode commune (template).

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 fournissez uniquement complexe opérateur :: * = (int) et complexe opérateur :: * = (double) et les versions autonomes seront déduits automatiquement :)

(1) Vous pouvez utiliser la valeur par défaut ici si tous les arguments sont intégrés. Vous pouvez également prendre en compte Boost.CallTraits, qui choisit automatiquement entre valeur par-value et by-ref selon que l'argument est intégré ou non. C'est pratique pour les modèles.

(2) Lors du retour des arguments en termes de valeur, il est non-sens de les qualifier const. Le mot-clé const signifie seulement quelque chose pour les références et les pointeurs, ici rien n'empêche l'utilisateur d'instancier un 'simple' Complex ...et vous avez de la chance, non!

1

Vous pourriez faire soit la classe réelle ou complexe auquel les opérateurs de multiplication non globales.

class Real 
{ 
    ........ 

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

}; 
0

Pouvez-vous faire des constructeurs complexes explicites? Cela signifie que la conversion implicite du réel au complexe n'est pas autorisé et doit désambiguïser l'opérateur *

+0

Les constructeurs devraient en effet être rendus explicites (question éditée). Cependant, dans ce cas, les rendre explicites n'éliminent pas l'erreur de compilation. – ASV

Questions connexes