web-dev-qa-db-fra.com

Surcharge des opérateurs sur les modèles de classe

Je ne parviens pas à définir des surcharges d'opérateur pour les classes de modèle. Prenons cette classe hypothétique par exemple.

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
    

Qu'est-ce que je fais mal ici?

12
Pieter
// 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;
}

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

Éditer: Techniquement, selon le standard, il est possible d’exporter des modèles, mais très peu de compilateurs le supportent. De plus, vous POUVEZ également faire ce qui précède si le modèle est explicitement instancié dans MyClass.cpp pour tous les types qui sont T mais qui en réalité défient normalement le point d’un modèle.

Plus de modifications: j'ai lu votre code et il a besoin de travail, par exemple l'opérateur de surcharge []. De plus, en général, je ferais en sorte que les dimensions fassent partie des paramètres du modèle, ce qui permettrait de détecter l'échec de + ou + = au moment de la compilation et de permettre au type d'être significativement alloué. Votre classe d'exception doit également dériver de std :: exception. Cependant, aucun de ceux-ci impliquent des erreurs de compilation, ils ne sont tout simplement pas un excellent code.

8
Puppy

Vous devez dire ce qui suit (puisque vous créez un lien avec un ensemble template au lieu d’une spécialisation, auquel cas il vous suffira d’ajouter un <> après le 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 de recevoir un warning , il semble que votre déclaration d’amitié ne soit pas une bonne idée. Si vous voulez simplement déclarer une seule spécialisation de celle-ci en tant qu'ami, vous pouvez le faire comme ci-dessous, avec une déclaration forward du modèle avant votre classe, de sorte que operator<< soit reconnu comme 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);

Tout ce qui précède et cette manière en déclarent les spécialisations en tant qu'amis, mais le premier déclare toutes les spécialisations en amis, tandis que le second déclare uniquement la spécialisation de operator<< en tant qu'ami dont T est égal à T de la classe qui accorde l'amitié . 

Et dans l’autre cas, votre déclaration a l’air OK, mais notez que vous ne pouvez pas += un MyClass<T> en MyClass<U> lorsque T et U sont de type différent avec cette déclaration (sauf si vous avez une conversion implicite entre ces types). Vous pouvez faire de 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;
}
12

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

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

Soln:

  1. En avant, déclarez la fonction ami avant la définition de la classe elle-même. Pour 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 la fonction de votre ami dans votre classe avec "<>" ajouté au nom de la fonction.

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

Vous devez spécifier que cet ami est une fonction modèle:

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

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

0
wilhelmtell