【问题标题】:External instantiation of nested template in another class另一个类中嵌套模板的外部实例化
【发布时间】:2019-01-06 17:09:02
【问题描述】:

我必须使用 class SmartPointer 对 int 指针列表进行排序。但在 liste2 类型的 class ListeTriee 的开头是 在 main.cpp 中实例化我收到一条错误消息:

来自编译器的错误消息

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

我认为在 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;
}

导致问题的行是这一行: ListeTriee&lt;SmartPointer&lt;int&gt; &gt; 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>;

我尝试了在 ListeTriee.cpp 末尾的显式实例化:template class ListeTriee&lt;SmartPointer&lt;int&gt; &gt;;,以便编译器可以使用给定的模板参数创建一个新类,但我得到的错误消息更大。

【问题讨论】:

  • 这既是代码太多(5 个源文件?真的吗?)又太少(缺少包含指令,缺少 ListeBase.h)。请尝试生成minimal reproducible example
  • 另外,请始终在您的代码中使用英文标识符和 cmets。
  • "我已经尝试过显式实例化:" 那么是什么让您认为没有它会更好呢?如果你使用一个类,你需要一个它的实例化,句号。如果由于某些错误而无法创建实例化,请询问那个错误

标签: c++ c++11 templates linker-errors smart-pointers


【解决方案1】:

您需要将显式实例化放入头文件中,以便编译器知道模板主体存在于某个翻译单元中,并且不会抱怨无法将模板主体放入当前翻译单元中。请注意,您将需要所有模板类的显式实例化,SmartPointer&lt;int&gt; 也是如此。

【讨论】:

  • "将显式实例化放入头文件" no.
【解决方案2】:

根据msdnSource code organization (C++ Templates), 在编译器不为模板或其任何成员生成目标代码的意义上,模板与普通类不同。在使用具体类型实例化模板之前,不会生成任何内容。当编译器遇到诸如 MyClass mc; 之类的模板实例化,并且尚不存在具有该签名的类时,它会生成一个新类。它还尝试为使用的任何成员函数生成代码。如果这些定义直接或间接地位于正在编译的 .cpp 文件中的未#included 文件中,则编译器将看不到它们。从编译器的角度来看,这不一定是错误,因为函数可能在另一个翻译单元中定义,在这种情况下链接器会找到它们。如果链接器没有找到该代码,则会引发未解决的外部错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多