Domanda

Ho appena creato questa nuova classe:

//------------------------------------------------------------------------------
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
//------------------------------------------------------------------------------
#include <vector>
#include <GL/GLFW.h>
//------------------------------------------------------------------------------
template<class T>
class MultithreadedVector {

    public:

        MultithreadedVector();

        void push_back(T data);

        void erase(typename std::vector<T>::iterator it);

        std::vector<T> get_container();
    private:

        std::vector<T> container_;
        GLFWmutex th_mutex_;


};
//------------------------------------------------------------------------------
#endif // MULTITHREADEDVECTOR_H_INCLUDED
//------------------------------------------------------------------------------

La definizione della classe:

//------------------------------------------------------------------------------
#include "MultithreadedVector.h"
//------------------------------------------------------------------------------
using namespace std;
//------------------------------------------------------------------------------
template<class T>
MultithreadedVector<T>::MultithreadedVector() {

    th_mutex_ = glfwCreateMutex();
}

template<class T>
void MultithreadedVector<T>::push_back(T data) {

    glfwLockMutex(th_mutex_);
    container_.push_back(data);
    glfwUnlockMutex(th_mutex_);

}

template<class T>
void MultithreadedVector<T>::erase(typename vector<T>::iterator it) {

    glfwLockMutex(th_mutex_);
    container_.erase(it);
    glfwUnlockMutex(th_mutex_);
}

template<class T>
vector<T> MultithreadedVector<T>::get_container() {


    return container_;

}

Ora il problema è che quando provo ad usarlo nel mio codice come membro statico di un'altra classe:

// VehicleManager.h
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

#include "MultithreadedVector.h"
#include "Vehicle.h"
class Foo {

   public:
     // stuffs
   private:
     static MultithreadedVector<Vehicle> vehicles_; 
     ...
}

#endif

Quindi all'interno: VehicleManager.cpp

#include "VehicleManager.h"

MultithreadedVector<Vehicle> VehicleManager::vehicles_;

void VehicleManager::Method() {

  Vehicle vehicle;
  VehicleManager::vehicles_.push_back(vehicle);

}

Ma non viene compilato :(, ottengo questo messaggio di errore ogni volta:

C:\***\VehicleManager.cpp|188|undefined reference to `MultithreadedVector<Vehicle>::push_back(Vehicle)'|

Non capisco davvero perché, in particolare ho definito il membro della classe statica nell'ambito globale di VehicleManager.cpp.

PS: sto usando Code :: Blocks.

Grazie!

È stato utile?

Soluzione

Questo è ciò che accadrà quando si sposta ciecamente un'implementazione del modello di classe in un file cpp.

Per farlo funzionare, devi sapere esattamente per quali tipi di T creerai un'istanza del modello di classe e specificali nel file cpp.

In questo caso, inseriscilo nel file cpp:

template class MultithreadedVector<Vehicle>;

Nota che il file cpp deve conoscere Veicolo quindi.

Altri suggerimenti

La maggior parte dei compilatori C ++ non consente di separare le dichiarazioni dei modelli e le definizioni dei modelli. Devi inserire la definizione completa delle tue classi di template in un singolo file .h, non dividerle in file .h e .cpp.

Il codice completo di implementazione del modello deve essere visibile al compilatore nel punto in cui vede l'uso del modello in modo da poter istanziare il modello e compilarlo in codice oggetto che può essere successivamente collegato.

Definire il codice modello nello stesso file di intestazione del modello dichiarato.

Penso che ci siano due casi in cui è possibile utilizzare i modelli

  1. Fornire codice generico per un insieme arbitrario di tipi conformi
  2. Fornire codice generico per un set fisso di tipi

Per il secondo, non è necessario inserire i modelli nell'intestazione: poiché si conosce in anticipo, precisamente, con quali tipi viene utilizzato il modello. Puoi definire molto bene la funzione membro di un modello di classe o un modello di funzione in un'unità di traduzione separata, senza errori del linker. Alcune persone continuano a insegnare ad altri che ciò non è possibile e confondono la questione con questo.

Ma penso che dipenda da questi due casi se si desidera separare la dichiarazione e la definizione in diverse unità di traduzione o meno.

  • Se si desidera utilizzare il caso 1, si desidera sempre avere la definizione nell'intestazione (se inclusa da file con nome speciale, come .ipp , .tcc o altro). Conosco solo un frontend C ++ che supporta la separazione delle definizioni dalle dichiarazioni anche in questo caso, che è il frontend EDG (edison design group), usato dai compilatori Intel e Comeau, che implementano export . Quella parola chiave è vista come un malfunzionamento da alcuni e la maggior parte dei compilatori non la implementa.

  • E se si desidera utilizzare il caso 2, non è utile inserire le definizioni nell'intestazione, poiché non vi sarebbe motivo di farlo: si creeranno istanze esplicite delle funzioni e delle classi necessarie per il set fisso di tipi. In questo secondo scenario, si utilizza il modello per salvarsi dall'onere per mantenere eventualmente il codice ridondante e si ha l'opzione aperta per introdurre comportamenti speciali per alcuni tipi in alcuni casi.

Il tuo scenario è chiaramente una situazione del primo caso, quindi dovrai inserire le tue definizioni nell'intestazione.

Sembra che si sia verificato un errore di copia e incolla in VehicleManager.h:

#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

Ciò proibisce l'inclusione del file header, dove è definita la classe Foo.

Nella maggior parte dei casi non è possibile scrivere l'implementazione del modello nel file cpp. Spostare l'implementazione del modello nel file di intestazione in modo che il compilatore possa istanziarlo correttamente.

A parte le altre risposte:

Devi anche proteggere get_container () . Questo metodo sostanzialmente copia gli elementi container_ e quindi deve essere protetto.

template<class T>
vector<T> MultithreadedVector<T>::get_container() 
{
    return container_;
}

Un modello in un certo senso è una specie di macro avanzata e specializzata. Non puoi effettivamente compilare una definizione di modello separatamente come sembra che tu stia provando a fare.

Per la maggior parte delle persone, ciò significa che non si preoccupano nemmeno di separare le definizioni della piastra dalle loro dichiarazioni. Ho un collega che fa un ulteriore passo avanti e si rifiuta di separare < em> definizioni e dichiarazioni non-template .

Se vuoi inserire la definizione di un modello dalla dichiarazione, hai comunque un paio di opzioni.

La prima opzione è usare il C ++ "export" parola chiave. Il problema con questa soluzione apparentemente semplice è che nessuno lo supporta . È troppo difficile da implementare per gli autori di compilatori.

La seconda opzione è quella di utilizzare un terzo tipo di file , spesso etichettato " .ipp " ;, per le dichiarazioni. Il trucco qui è che è ancora un file che deve essere " # incluso " ;, ma essendo un file separato, devi solo includerlo in " .cpp " File. Ho trovato che il mio linker non mi piace se #include un " .ipp " in più di un ".cpp" file in un singolo programma, quindi devi sceglierne uno come inclusore.

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