Question

Je viens de créer cette nouvelle 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 définition de la 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_;

}

Le problème est que lorsque j'essaie de l'utiliser dans mon code en tant que membre statique d'une autre 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

Puis à l'intérieur: VehicleManager.cpp

#include "VehicleManager.h"

MultithreadedVector<Vehicle> VehicleManager::vehicles_;

void VehicleManager::Method() {

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

}

Mais cela ne compile pas :(, je reçois cette erreur chaque fois:

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

Je ne comprends vraiment pas pourquoi, surtout que j'ai défini le membre de classe statique dans la portée globale de VehicleManager.cpp.

PS: j'utilise Code :: Blocks.

Merci!

Était-ce utile?

La solution

C’est ce qui se produira lors du déplacement aveugle d’une implémentation de modèle de classe dans un fichier cpp.

Pour que cela fonctionne, vous devez savoir exactement pour quels types de T vous allez instancier le modèle de classe et les spécifier dans le fichier cpp.

Dans ce cas, mettez ceci dans le fichier cpp:

template class MultithreadedVector<Vehicle>;

Notez que le fichier cpp doit connaître Vehicle , puis.

Autres conseils

La plupart des compilateurs C ++ n'autorisent pas la séparation des déclarations de modèles et des définitions de modèles. Vous devez placer la définition complète de vos classes de modèles dans un seul fichier .h, et non les scinder en fichiers .h et .cpp.

Le code complet de l'implémentation du modèle doit être visible par le compilateur au moment où il voit l'utilisation du modèle afin qu'il puisse instancier le modèle et le compiler en code objet pouvant être lié ultérieurement.

Définissez le code du modèle dans le même fichier d'en-tête que le modèle est déclaré.

Je pense qu'il y a deux cas d'utilisation de modèles

  1. Fourniture d'un code générique pour un ensemble arbitraire de types conformes
  2. Fourniture de code générique pour un ensemble fixe de types

Pour le second, vous n'avez pas besoin de mettre des modèles dans l'en-tête: puisque vous savez à l'avance, précisément, avec quels types votre modèle est utilisé. Vous pouvez très bien définir la fonction membre d'un modèle de classe ou un modèle de fonction dans une unité de traduction distincte, sans erreur de l'éditeur de liens. Certaines personnes continuent d'enseigner aux autres que cela n'est pas possible, et confondent les choses.

Mais je pense que cela dépend de ces deux cas si vous souhaitez séparer déclaration et définition en unités de traduction différentes ou non.

  • Si vous voulez utiliser le cas 1, vous voulez toujours avoir la définition dans l'en-tête (qu'elle soit incluse dans des fichiers nommés spéciaux, comme .ipp , .tcc ou autre chose). Je ne connais qu'une interface C ++ prenant en charge la séparation de la définition des déclarations, même dans ce cas, l'interface EDG (edison design group), utilisée par les compilateurs Intel et Comeau, qui implémente export . Ce mot-clé est considéré par certains comme une mauvaise utilisation et la plupart des compilateurs ne l'implémentent pas.

  • Et si vous voulez utiliser le cas 2, il n'est pas bon de mettre les définitions dans l'en-tête, car il n'y aurait aucune raison de le faire: vous allez simplement instancier explicitement les fonctions et les classes nécessaires pour le jeu de correctifs de types. Dans ce deuxième scénario, vous utilisez le modèle pour vous épargner la tâche de maintenir du code éventuellement redondant et vous avez la possibilité d'ouvrir un comportement spécial pour certains types dans certains cas.

Votre scénario est clairement un cas 1 et vous devrez donc mettre vos définitions dans l'en-tête.

Vous semblez avoir une erreur copier / coller dans VehicleManager.h:

#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

Ceci interdit l'inclusion du fichier d'en-tête, où la classe Foo est définie.

Vous ne pouvez pas écrire l'implémentation du modèle dans le fichier cpp dans la plupart des cas. Déplacez le modèle d'implémentation dans le fichier d'en-tête afin que le compilateur puisse l'instancier correctement.

En dehors des autres réponses:

Vous devez également protéger get_container () . Cette méthode copie les éléments conteneur _ et doit donc être protégée.

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

Un modèle est en quelque sorte une sorte de macro avancée et spécialisée. Vous ne pouvez pas réellement compiler une définition de modèle séparément, comme si vous essayiez de la créer.

Pour la plupart des gens, cela signifie qu'ils ne se soucient même pas de séparer les définitions de moteur de leurs déclarations. J'ai un collègue qui va plus loin et refuse de séparer < em> définitions et déclarations non-template également.

Si vous souhaitez définir la définition d'un modèle à partir de la déclaration, vous disposez de plusieurs options.

La première option consiste à utiliser le " export " C ++ mot-clé. Le problème de cette solution apparemment simple est que personne ne la prend en charge. . Il est trop difficile à implémenter pour les rédacteurs de compilateur.

La deuxième option consiste à utiliser un troisième type de fichier , souvent étiquetés ".ipp", pour les déclarations. Le truc, c’est que c’est toujours un fichier qui doit être "# inclus", mais étant un fichier séparé, il vous suffit de l’inclure dans ".cpp". des dossiers. J'ai trouvé que mon éditeur de liens n'aimait pas cela si j'incluais un ".ipp". dans plus d'un ".cpp" fichier dans un seul programme, de sorte que vous devez en choisir un qui soit l'incluseur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top