5

Hey, j'obtiens une erreur de lieur LNK2019: symbole externe non résolu en essayant d'utiliser un opérateur + surchargé. Je vais vous montrer snip-its de la classe, et comment je l'utilise dans le principal. Si vous avez besoin de voir plus, faites le moi savoir, je vais juste essayer de garder les choses concises.Surcharge + opérateur avec des modèles

/** vec.h **/ 
#ifndef __VEC_H_ 
#define __VEC_H_ 

#include <iostream> 
#include <vector> 

namespace xoor{ 

    template<typename T> 
    class vec{ 

    public: 
     inline friend vec<T> operator + (const vec<T>&, const vec<T>&); 
     inline const vec<T>& operator += (const vec<T>&); 

    private: 
     std::vector<T> m_index; 
    }; // Vec. 


    template<typename T> 
    vec<T>& operator + (const vec<T>& a, const vec<T>& b){ 
     vec<T> product = a; 
     product += b; 

     return product; 
    } // Addition. 

    template<typename T> 
    const vec<T>& vec<T>::operator += (const vec<T>& v){ 
     for (unsigned short i =0; i < m_index.size(); ++i){ 
      if (i >= v.size()) 
       break; 
      m_index[i] += v.getIndex()[i]; 
     } 

     return * this; 
    } // Addition Compound. 


} // xoor 

#endif // __VEC_H_ 

Notez que j'ai [] surchargée aussi bien, donc je vais juste accéder à certaines parties de m_index avec elle. getIndex() retourne juste m_index. Et la taille() retourne m_index.size()

/** main.cpp **/ 

#include <iostream> 
#include "vec.h" 

void testHook(); 

int main(){ 
    testHook(); 
    system("PAUSE"); 
    return 0; 
} 

void testHook(){ 
    using namespace xoor; 
    vec<double> vA(3); // passing 3 for 3 elements 
    vec<double> vB(3); 

    // v + v 
    std::cout << "\n\tA + B = "; 
    vec<double> vAB(3); 
    vAB = vA + vB; // PRODUCES THE LNK2019 
    vAB.print(std::cout); // Outputs the vec class to the console. 
} 

Message d'erreur:

Error 1 error LNK2019: unresolved external symbol "class xoor::vec<double> __cdecl xoor::operator+(class xoor::vec<double> const &,class xoor::vec<double> const &)" ([email protected]@[email protected]@[email protected]@[email protected]) referenced in function "void __cdecl testHook(void)" ([email protected]@YAXXZ) main.obj 

Mise à jour:

Voici maintenant directement au-dessus de la définition de la classe. Je continue d'avoir la même erreur de lien, comme décrit ci-dessus.

template<typename T> 
    class vec; 

    template<typename T> 
    vec<T> operator + (const vec<T>&, const vec<T>&); 

Mise à jour 2: Solution.

La mise à jour ci-dessus est incorrecte. La solution de sbi a fonctionné, je n'ai pas réussi à modéliser l'opérateur comme suit.

template<typename T> 
    vec<T> operator +<T> (const vec<T>&, const vec<T>&); 

sbi, et David discutaient de la raison pour laquelle j'utilisais des amis en premier lieu. Initialement je les utilisais, parce que vous ne pouvez pas passer deux paramètres à un opérateur binaire surchargé tel que +, et les amis immédiatement sollicités comme solution. Comme il s'avère, vous pouvez toujours utiliser l'opérateur binaire assez facilement avec un seul paramètre. Voici la solution finale.

// ... 
template<typename T> 
class vec{ 
    public: 
    const vec<T> operator + (const vec<T>&, const vec<T>&)const; 
    // ... 

}; // Vec. 

template<typename T> 
const vec<T> vec<T>::operator + (const vec<T>& v)const{ 
    matrix<T> product = *this; 
    vec(product += v); 
} // Addition. 

Aussi, pour toute personne d'autre lecture de cela, la peine de vérifier les notes de l'OSMŒ au fond de sa réponse. Il y a des choses que je fais qui sont superflues.

Merci pour l'aide à tous. Codage heureux.

+0

S'il s'agit de devoirs (et cela vous semble suspect), vous devez ajouter l'étiquette 'devoirs '. Beaucoup d'entre nous répondent différemment aux questions de devoirs, de sorte que vous en apprenez le plus possible (alors que d'autres questions sont habituellement posées pour que ceux qui posent la question puissent continuer à faire ce qu'ils font le plus vite possible). – sbi

Répondre

7

Pour lier d'amitié avec un modèle, je pense que vous devez déclarer ce modèle avant la définition de classe dans laquelle vous voulez vous lier d'amitié. Cependant, pour que cette déclaration compile, vous devez déclarer le modèle de classe. Donc, cela devrait fonctionner:

template<typename T> 
class vec; 

template<typename T> 
vec<T> operator + (vec<T>, const vec<T>&); 

template<typename T> 
class vec{ 
public: 
    friend vec<T> operator +<T> (vec<T>, const vec<T>&); 
// ... 

Cette lie d'amitié avec une instance spécifique du modèle de fonction operator+(), à savoir operator+<T>. (Vous pouvez également lier d'amitié avec toutes les instances d'un modèle:

// no forward declarations necessary 

template<typename T> 
class some_class { 
    template<typename U> 
    friend void f(vec<U>&); 
    // ... 
}; 

Cependant, c'est moins souvent utile que l'autre.)

Edit: Un commentaire de David m'a fait penser (aurais dû faire cela depuis le début) et qui conduisent à la découverte que la déclaration friend est inutile!. Votre operator+ utilise uniquement une fonction membre public de vec (operator+=) et n'a donc pas besoin d'être un friend de la classe. Donc, ce qui précède simplifierait à

template<typename T> 
class vec{ 
public: 
    // ... 
}; 

template<typename T> 
vec<T> operator + (vec<T> a, const vec<T>& b){ 
    a += b; 
    return a; 
} 

Voici quelques notes:

  • operator+() (qui vous bien implanté au dessus de operator+=(), BTW) devrait prendre son argument gauche par copie.
  • Ne pas déclare fonctions inline, définissent les ainsi.
  • Renvoyer une référence non const car tout le monde s'attend à ce que f(m1+=m2) fonctionne même si f() prend son argument comme référence non const.
  • À l'intérieur d'un modèle de classe, dans la plupart des endroits, vous pouvez omettre la liste des paramètres du modèle lorsque vous faites référence à la classe. Donc, vous pouvez dire vec& operator += (const vec&);. (Vous ne pouvez pas le faire en dehors du modèle, bien que - par exemple, lors de la définition que l'opérateur en dehors de la classe.)
  • Un type d'index de std::vector est orthographié std::vector<blah>::size_type, pasunsigned short.
+0

Merci pour la réponse, et l'échantillon. Malheureusement, cela n'a pas fonctionné. Je vais continuer à essayer quelques petites choses. Si vous pensez à quelque chose, je reviendrai régulièrement. – Xoorath

+0

@Xoorath: "Ça ne marche pas" est trop vague pour pouvoir dire quoi que ce soit. (J'ai en fait une version ici qui compile et lie avec VC, donc je sais que cela fonctionne en principe.) – sbi

+0

Désolé mon pote. Une seconde. Je vais mettre à jour mon extrait de code. – Xoorath

7

Le type de retour ici:

inline friend vec<T> operator + (const vec<T>&, const vec<T>&); 

ne correspond pas ici:

template<typename T> 
    vec<T>& operator + (const vec<T>& a, const vec<T>& b){ 
     vec<T> product = a; 
     product += b; 

     return product; 
    } // Addition. 
+0

En outre, ce n'est pas la fonction __declarations__ qui doit être marquée comme 'inline', mais la fonction __definitions__. Il est donc 'ami VEC opérateur + (const VEC &, const VEC &);' et 'const VEC & opérateur + = (const VEC &);', mais 'en ligne VEC opérateur + (const VEC &, const vec &) {...} 'et' const vec & operator + = (const vec &) {...} '. Oh, et quelle est la raison pour laquelle '+ =' renvoie un 'const vec &'? Je pense que cela devrait être une référence non-'const '. – sbi

+1

Encore une chose (en fait, j'aurais dû faire ma propre réponse ...): Comme les opérandes laissés en opération seront copiés tout de suite, cet argument devrait être passé par copie au lieu d'une référence 'const'. Cela a été vu différemment (la copie est un détail d'implémentation et ne devrait pas fuir dans l'interface), mais les gens intelligents ont découvert que faire la copie en passant l'argument donne aux compilateurs quelques opportunités d'optimisation supplémentaires (par exemple, l'opérande est un temporaire qui va être détruit de toute façon). – sbi

+0

Merci beaucoup monsieur. – Xoorath