Waarom krijg ik “onopgeloste externe symbolen”-fouten bij het gebruik van sjablonen?

Als ik C++-code voor een klasse schrijf met behulp van sjablonen en de code splits tussen een bronbestand (CPP) en een koptekstbestand (H), krijg ik een heleboel “onopgeloste externe symbool” -fouten als het gaat om het koppelen van de uiteindelijk uitvoerbaar, ondanks dat het objectbestand correct is opgebouwd en in de koppeling is opgenomen. Wat gebeurt hier en hoe kan ik dit oplossen?


Antwoord 1, autoriteit 100%

Klassen en functies met sjablonen worden pas geïnstantieerd als ze worden gebruikt, meestal in een afzonderlijk .cpp-bestand (bijvoorbeeld de programmabron). Wanneer de sjabloon wordt gebruikt, heeft de compiler de volledige code voor die functie nodig om de juiste functie met het juiste type te kunnen bouwen. In dit geval is de code voor die functie echter gedetailleerd in het bronbestand van de sjabloon en is daarom niet beschikbaar.

Als resultaat van dit alles neemt de compiler gewoon aan dat het ergens anders is gedefinieerd en voegt alleen de aanroep van de sjabloonfunctie in. Als het gaat om het compileren van het bronbestand van de sjabloon, wordt het specifieke sjabloontype dat in de programmabron wordt gebruikt daar niet gebruikt, dus het genereert nog steeds niet de code die nodig is voor de functie. Dit resulteert in het onopgeloste externe symbool.

De beschikbare oplossingen hiervoor zijn:

  1. omvatten de volledige definitie van
    de ledenfunctie in de
    template’s header-bestand en niet hebben
    een bronbestand voor de sjabloon,
  2. definieer alle lidfuncties in
    het bronbestand van de sjabloon als
    “inline”
    (Update: [dit werkt niet op Visual Studio 2017+]), of
  3. definieer het lid
    functies in de bron van de sjabloon
    met het trefwoord “exporteren”.
    Dit wordt helaas niet ondersteund
    door veel compilers.
    (Update: dit is verwijderd uit de standaard vanaf C++11.)

Zowel 1 als 2 lossen het probleem in principe op door de compiler toegang te geven tot de volledige code voor de sjabloonfunctie wanneer deze probeert de getypte functie in de programmabron te bouwen.


Antwoord 2, autoriteit 14%

Een andere optie is om de code in het cpp-bestand te plaatsen en in hetzelfde cpp-bestand expliciete instanties van de sjabloon toe te voegen met de typen die u verwacht te gebruiken. Dit is handig als je weet dat je het alleen gaat gebruiken voor een paar soorten die je van tevoren kent.


Antwoord 3

Voor elk bestand dat het .h-bestand bevat, moet u beide regels invoegen:

#include "MyfileWithTemplatesDeclaration.h"
#include "MyfileWithTemplatesDefinition.cpp"

voorbeeld

#include "list.h"
    #include "list.cpp" //<---for to fix bug link err 2019
    int main(int argc, _TCHAR* argv[])
    {
        list<int> my_list;
        my_list.add_end(3);
    .
    .
    } 

Vergeet ook niet om uw declaratieklasse tussen centinelconstanten te plaatsen

#ifndef LIST_H
#define LIST_H
#include <iostream>
.
.
template <class T>
class list
{
private:
    int m_size,
        m_count_nodes;
    T m_line;
    node<T> *m_head;
public:
    list(void);
    ~list(void);
    void add_end(T);
    void print();
};
#endif

Other episodes