0

I have to sort a list of int pointers with a class SmartPointer. But in the beginning where the object liste2 of the type class ListeTriee is instantiated in main.cpp I receive an error message:

Error message from compiler

Undefined symbols for architecture x86_64:
  "ListeTriee<SmartPointer<int> >::ListeTriee()", referenced from:
      _main in main.cpp.o
  "ListeTriee<SmartPointer<int> >::~ListeTriee()", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture x86_64

I think the problem occurs when instantiating a template with the given template argument in ListeTriee.cpp.

MacBook Pro, CLion 2016.3.2

Main.cpp

int main()
{
    cout << "*** 7. Liste triee de pointeurs de int AVEC SmartPointer ***************************************************" << endl;
      ListeTriee<SmartPointer<int> > liste2;
        /*
      liste2.insere(new int (5));   // ne pas oublier de redefinir operator= de SmartPointer !!!
      liste2.insere(new int (2));
      liste2.insere(new int (8));
      liste2.insere(new int (3));
      liste2.Affiche(); // redefinir operator<< de SmartPointer de telle sorte qu'il affiche la valeur du pointeur

return 0;
}

The line that causes problems is this one: ListeTriee<SmartPointer<int> > liste2;

SmartPointer.h

    #ifndef C_PROGRAMM8_SMARTPOINTER_H
    #define C_PROGRAMM8_SMARTPOINTER_H

    #include <iostream>
    #include <stdlib.h>
    #include "Ligne.h"

    using namespace std;
    template <class T> class SmartPointer{
    private:
        T *val;
    public:
        //Constructeurs
        SmartPointer<T>();
        SmartPointer<T>(SmartPointer<T> *);
        SmartPointer<T>(T *);

        //Destructeur
        ~SmartPointer<T>();

        //Surcharge d'opérateurs
        bool operator <(const SmartPointer &) const;                  //<
        friend ostream &operator<<(ostream &, SmartPointer<T> *);
        T* operator->() const;
        T& operator*() const;

        //Getter
        T* getVal() const;

        //Autre
        void Delete();
    };
    #endif //C_PROGRAMM8_SMARTPOINTER_H

SmartPointer.cpp

#include "SmartPointer.h"
template <class T>
SmartPointer<T>::SmartPointer() {
    cout << "-> Constructeur par defaut [SmartPointer]" << endl;

    val = NULL;
}
template <class T>
SmartPointer<T>::SmartPointer(T *new_Val) {
    cout << "-> Constructeur d initialisation [SmartPointer]" << endl;

    val = new_Val;
}
template <class T>
SmartPointer<T>::SmartPointer(SmartPointer<T> *new_SmartPointer) {
    cout << "-> Constructeur de copie [SmartPointer]" << endl;

    *val = *(new_SmartPointer -> val);
}
template <class T>
SmartPointer<T>::~SmartPointer() {
    cout << "-> Destructeur [SmartPointer]" << endl;
}
template <class T>
bool SmartPointer<T>::operator<(const SmartPointer &new_SmartPointer) const {
    if(*val < *(new_SmartPointer.val))
        return true;
    else
        return false;
}
template <class T>
T& SmartPointer<T>::operator*() const {
    return *val;
}
template <class T>
T* SmartPointer<T>::operator->() const {
    return val;
}
template <class T>
void SmartPointer<T>::Delete() {
    cout << "-> Appel a 'Delete' de l objet pointee" << endl;
    if(val != NULL)
        delete val;
}
template <class T>
T *SmartPointer<T>::getVal() const {
    return val;
}
template <class T>
ostream &operator<<(ostream &new_Out, SmartPointer<T> *new_SmartPointer){
    new_Out << new_SmartPointer;

    return new_Out;
}
template class SmartPointer<int>;
template class SmartPointer<Ligne>;

ListeTriee.h

#ifndef C_PROGRAMM6_LISTETRIEE_H
#define C_PROGRAMM6_LISTETRIEE_H

#include "ListeBase.h"
template <class T>
class ListeTriee : public ListeBase<T>{
public:
    //Constructeurs
    ListeTriee();
    ListeTriee(const ListeTriee &);
    //Destructeurs
    virtual ~ListeTriee();
    //Methodes virtual
    virtual T *insere(const T &);
};
#endif //C_PROGRAMM6_LISTETRIEE_H

ListeTriee.cpp

#include "ListeTriee.h"
template <class T>
ListeTriee<T>::ListeTriee() : ListeBase<T>(){
    cout << "-> Constructeur par defaut [ListeTriee]" << endl;
}
template <class T>
ListeTriee<T>::ListeTriee(const ListeTriee & new_ListeTriee) : ListeBase<T>(new_ListeTriee){
    cout << "-> Constructeur de copie [ListeTriee]" << endl;
}
template <class T>
ListeTriee<T>::~ListeTriee() {
    cout << "Destructeur [ListeTriee]" << endl;
}
template <class T>
T* ListeTriee<T>::insere(const T &new_T) {
    Cellule<T> *TmpPrec, *Tmp, *Ajout;

    Ajout = new Cellule<T>;

    Ajout -> valeur = new_T;
    Ajout -> suivant = NULL;

    if(this -> ptete == NULL) {
        this->ptete = Ajout;
    }
    else{

        TmpPrec = NULL;
        Tmp = this -> ptete;

        while(Tmp -> suivant != NULL && Ajout -> valeur > Tmp -> valeur){
            TmpPrec = Tmp;
            Tmp = Tmp -> suivant;

        }
        if(Ajout -> valeur <= Tmp -> valeur)
        {

            //Nouvelle valeur va être placée au début de la liste
            if(TmpPrec == NULL)
            {
                Ajout -> suivant = this -> ptete;
                this -> ptete = Ajout;
            }
            else{   //Val se trouve entre la position 1 et n - 1
                TmpPrec -> suivant = Ajout;
                Ajout -> suivant = Tmp;
            }

        }
        else
        {   //Élément se trouve à la fin de la liste
            Tmp -> suivant = Ajout;
            Ajout -> suivant = NULL;
        }
    }
    //cout << Ajout -> valeur << endl;

    return &Ajout -> valeur;
}
template class ListeTriee<int*>;
template class ListeTriee<int>;
template class Cellule<int>;
template class ListeTriee<Couleur>;

I have tried the explicit instantiation: template class ListeTriee<SmartPointer<int> >; at the end of ListeTriee.cpp so that the compiler can create a new class with the given template argument but the error message I get is even bigger.

user7860670
  • 35,849
  • 4
  • 58
  • 84
Daniel B
  • 91
  • 1
  • 5
  • 1
    This is both too much code (5 source files? Really?) and too little (missing include directives, missing ListeBase.h). Please try producing a [mcve]. – n. m. could be an AI Jul 30 '18 at 14:08
  • Also please always use English identifiers and comments in your code. – n. m. could be an AI Jul 30 '18 at 14:12
  • "I have tried the explicit instantiation:" So what made you think you would be better off without it? If you use a class, you need an instantiation of it, period. If you cannot create an instantiation because of some error, *ask about **that** error*. – n. m. could be an AI Jul 30 '18 at 14:16

2 Answers2

0

You need to put explicit instantiation into header file so compiler will know that template body exists in some translation unit and won't complain about not being able to put template body into current translation unit. Note that you will need explicit instantiations of all the template classes, that is for SmartPointer<int> as well.

user7860670
  • 35,849
  • 4
  • 58
  • 84
0

According to msdn Source code organization (C++ Templates), Templates are not like ordinary classes in the sense that the compiler does not generate object code for a template or any of its members. There is nothing to generate until the template is instantiated with concrete types. When the compiler encounters a template instantiation such as MyClass mc;, and no class with that signature exists yet, then it generates a new class. It also attempts to generate code for any member functions that are used. If those definitions are in a file that is not #included, directly or indirectly, in the .cpp file that is being compiled, the compiler can't see them. From the compiler's point of view, this isn't necessarily an error because the functions may be defined in another translation unit, in which case the linker will find them. If the linker does not find that code, it raises an unresolved external error.

ctor1979
  • 1
  • 2