2010-10-25 4 views
11

Je rencontre des problèmes pour définir certaines surcharges d'opérateur pour les classes de modèles. Prenons cette classe hypothétique par exemple.Surcharge de l'opérateur sur les modèles de classe

template <class T> 
class MyClass { 
    // ... 
}; 
  • opérateur + =

    // In MyClass.h 
    MyClass<T>& operator+=(const MyClass<T>& classObj); 
    
    
    // In MyClass.cpp 
    template <class T> 
    MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) { 
        // ... 
        return *this; 
    } 
    

    résultats dans cette erreur du compilateur:

    no match for 'operator+=' in 'classObj2 += classObj1' 
    
  • opérateur < <

    // In MyClass.h 
    friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 
    
    
    // In MyClass.cpp 
    template <class T> 
    std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj) { 
        // ... 
        return out; 
    } 
    

    résultats dans cet avertissement du compilateur:

    friend declaration 'std::ostream& operator<<(std::ostream&, const MyClass<T>&)' declares a non-template function 
    

ce que je fais mal ici?

+0

peut vous envoyer un code réel qui ne parvient pas à compiler? – Naveen

+0

@Naveen: vous pouvez obtenir une version compressée sur http://www.box.net/shared/v23rj2f8e7 – Pieter

Répondre

7
// In MyClass.h 
MyClass<T>& operator+=(const MyClass<T>& classObj); 


// In MyClass.cpp 
template <class T> 
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) { 
    // ... 
    return *this; 
} 

Ce n'est pas valable pour les modèles. Le code source complet de l'opérateur doit être dans toutes les unités de traduction dans lesquelles il est utilisé. Cela signifie généralement que le code est en ligne dans l'en-tête.

Éditer: Techniquement, selon la norme, il est possible d'exporter des modèles, mais très peu de compilateurs le supportent. En outre, vous pouvez également faire ce qui précède si le modèle est explicitement instancié dans MyClass.cpp pour tous les types T- mais en réalité, qui défie normalement le point d'un modèle.

Plus d'édition: Je lis votre code, et il a besoin de travail, par exemple surcharge l'opérateur []. De plus, typiquement, je ferais en sorte que les dimensions fassent partie des paramètres du gabarit, ce qui permettrait de récupérer l'erreur de + ou + = au moment de la compilation et de permettre l'allocation significative du type de pile. Votre classe d'exception doit également provenir de std :: exception. Cependant, aucun d'entre eux n'implique des erreurs de compilation, ce n'est pas du bon code.

0

Vous devez spécifier que l'ami est une fonction de modèle:

MyClass<T>& operator+=<>(const MyClass<T>& classObj); 

Voir this C++ FAQ Lite réponse pour plus de détails.

12

Vous devez dire ce qui suit (puisque vous lier d'amitié avec un modèle tout au lieu d'une spécialisation de celui-ci, auquel cas vous auriez juste besoin d'ajouter un <> après la operator<<):

template<typename T> 
friend std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 

En fait, il n'est pas nécessaire de le déclarer comme ami sauf s'il accède à des membres privés ou protégés. Puisque vous venez d'obtenir un avertissement, il semble que votre déclaration d'amitié n'est pas une bonne idée. Si vous souhaitez simplement déclarer une spécialisation unique en tant qu'ami, vous pouvez le faire comme indiqué ci-dessous, avec une déclaration avant du modèle avant votre classe, afin que operator<< soit reconnu comme un modèle.

// before class definition ... 
template <class T> 
class MyClass; 

// note that this "T" is unrelated to the T of MyClass ! 
template<typename T> 
std::ostream& operator<<(std::ostream& out, const MyClass<T>& classObj); 

// in class definition ... 
friend std::ostream& operator<< <>(std::ostream& out, const MyClass<T>& classObj); 

Les deux ci-dessus et ainsi déclarer spécialisations comme amis, mais le premier déclare toutes spécialisations comme des amis, tandis que le second déclare que la spécialisation de operator<< comme un ami dont T est égale à la T de la classe accordant l'amitié.

Et dans l'autre cas, votre déclaration semble OK, mais notez que vous ne pouvez pas += un MyClass<T> à un MyClass<U> quand T et U sont différents types avec cette déclaration (sauf si vous avez une conversion implicite entre ces types). Vous pouvez faire votre += un modèle de membre

// In MyClass.h 
template<typename U> 
MyClass<T>& operator+=(const MyClass<U>& classObj); 


// In MyClass.cpp 
template <class T> template<typename U> 
MyClass<T>& MyClass<T>::operator+=(const MyClass<U>& classObj) { 
    // ... 
    return *this; 
} 
2

http://www.parashift.com/c++-faq-lite/template-friends.html

Cela m'a aidé avec le même problème.

Soln:

  1. déclarer avant la fonction ami avant la définition de la classe elle-même. Ex:

    template<typename T> class MyClass; // pre-declare the template class itself 
        template<typename T> std::ostream& operator<< (std::ostream& o, const MyClass <T>& x); 
    
  2. Déclarez votre fonction ami dans votre classe « <> » ajouté au nom de la fonction.

    friend std::ostream& operator<< <> (std::ostream& o, const Foo<T>& x); 
    
+0

Le lien mène au délai d'expiration. – TobiMcNamobi

-1

De cette façon fonctionne:

class A 
{ 
    struct Wrap 
    { 
     A& a; 
     Wrap(A& aa) aa(a) {} 
     operator int() { return a.value; } 
     operator std::string() { stringstream ss; ss << a.value; return ss.str(); } 
    } 
    Wrap operator*() { return Wrap(*this); } 
}; 
Questions connexes