Domanda

Ho ben poca idea di cosa succeda per quanto riguarda i modelli C ++, ma sto cercando di implementare una funzione che cerca un vettore per un elemento che soddisfa una determinata proprietà (in questo caso, cercandone uno con il nome indicato). La mia dichiarazione nel mio file .h è la seguente:

template <typename T>
T* find_name(std::vector<T*> v, std::string name);

Quando compilo, ottengo questo errore del linker quando chiamo la funzione:

Error   1   error LNK2019: unresolved external symbol "class Item * __cdecl find_name<class Item>(class std::vector<class Item *,class std::allocator<class Item *> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??$find_name@VItem@@@@YAPAVItem@@V?$vector@PAVItem@@V?$allocator@PAVItem@@@std@@@std@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z) referenced in function "public: class Item * __thiscall Place::get_item(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?get_item@Place@@QAEPAVItem@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) place.obj   Program2

Ancora una volta, sono nuovo nei template, quindi non so cosa stia succedendo. Tutte le istanze che ho riscontrato su LNK2019 tramite Google riguardano il non utilizzo delle librerie corrette, ma poiché questa è la mia funzione non vedo perché ciò accada.

Inoltre, una domanda correlata: esiste un modo per creare un parametro template in modo che debba essere una sottoclasse di una determinata classe, ovvero template?

È stato utile?

Soluzione

Devi avere le definizioni dei tuoi modelli disponibili sul sito chiamante. Ciò significa che nessun file .cpp .

Il motivo è che i modelli non possono essere compilati. Pensa alle funzioni come ai cookie e il compilatore è un forno.

I modelli sono solo un cookie cutter, perché non sanno che tipo di cookie sono. Indica solo al compilatore come eseguire la funzione quando viene assegnato un tipo, ma di per sé non può essere utilizzato perché non esiste alcun tipo concreto su cui operare. Non puoi cucinare un tagliabiscotti. Solo quando hai preparato il gustoso impasto per biscotti (ovvero, dato al compilatore l'impasto [tipo])) puoi tagliare il biscotto e cucinarlo.

Allo stesso modo, solo quando si utilizza effettivamente il modello con un certo tipo, il compilatore può generare la funzione effettiva e compilarla. Non può farlo, tuttavia, se manca la definizione del modello. Devi spostarlo nel file di intestazione, in modo che il chiamante della funzione possa creare il cookie.

Altri suggerimenti

Probabilmente stai soffrendo la mancanza di un'istanza valida. Se si inserisce la definizione del modello in un file .cpp separato, quando il compilatore compila quel file potrebbe non sapere quali istanze siano necessarie. Viceversa, nei siti di chiamata che creerebbero un'istanza della versione corretta della funzione modello, se la definizione del corpo della funzione non è disponibile, il compilatore non avrà le informazioni per creare un'istanza delle specializzazioni richieste.

Hai due opzioni. Inserisci il corpo della funzione per il modello di funzione nel file di intestazione.

es. nel file di intestazione:

template <typename T>
inline T* find_name(std::vector<T*> v, std::string name)
{
    // ...
}

o crea un'istanza esplicita del modello in .cpp dove hai definito il modello.

es. nel file sorgente (probabilmente richiederà #include nel file che definisce Item ):

template <typename T>
T* find_name(std::vector<T*> v, std::string name)
{
    // ...
}

template Item* find_name<Item>(std::vector<Item*> v, std::string name);

Le risposte qui sono fantastiche.

Aggiungo semplicemente che questo è spesso il motivo per cui oltre ai file .h e .cpp in un progetto. Troverai spesso file .inl . Le definizioni del modello andranno nel file .inl .

Questi file .inl significano in linea e di solito saranno inclusi dal file .h con lo stesso prefisso nella parte inferiore del file dopo tutte le dichiarazioni di intestazione. Ciò li rende effettivamente parte del file di intestazione ma separa le dichiarazioni da qualsiasi definizione.

Dato che sono file di intestazione glorificati, dovresti prendere tutte le stesse precauzioni che avresti con un normale file di intestazione, ad esempio includendo guardie ecc.

Ci siamo imbattuti nello stesso problema e ho trovato questo che indica 3 soluzioni alternative: http: / /www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-ah-file-and-imp

Tra questi ce n'è uno facile in cui crei un "fittizio" metodo nel file .cpp, che chiama la funzione template / class con i diversi tipi. Incollato dal link:

// No need to call this TemporaryFunction() function, it's just to avoid link error.
void TemporaryFunction ()
{
    TestTemp<int> TempObj;
    TestTemp<float> TempObj2;
}

Ho appena notato che hai avuto una seconda domanda che sembra non avere risposta:

  

Esiste un modo per creare un parametro template in modo che debba essere una sottoclasse di una determinata classe, ovvero template?

È possibile. Ad esempio, vedi is_base_of in Boost.TypeTraits .

Tuttavia, sono curioso: perché lo vuoi? Normalmente, i requisiti di un modello sui suoi parametri non sono sul tipo di parametro stesso, ma su quali espressioni che coinvolgono quel tipo sono legali. Ad esempio, immagina di avere:

template<class T>
void foo(const T& t)
{
    if (t.foo()){
       t.bar("blah");
    }
}

Dire che T deve ereditare da qualcosa del tipo:

class HasFooAndBar
{
public:
  void foo()const;
  void bar(const char*)const;
};

non porta nulla perché l'istanza della funzione fallirà comunque se il tipo non supporta le operazioni. Inoltre, limita inutilmente l'applicabilità di foo () . In realtà, qualsiasi requisito di foo è che t.foo () e t.bar (const char *) sono espressioni valide su una const T. Ad esempio, questo tipo non eredita da HasFooAndBar ed è ancora un parametro foo () valido:

struct DifferentFromHasFooAndBar
{
  bool foo()const;
  std::string bar(const std::string&)const;
};

Hai inserito la definizione della funzione del tuo modello in un file cpp? Quindi spostalo nell'intestazione e incorporalo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top