Exportation et importation de templates

De RAD Studio
Aller à : navigation, rechercher

Remonter à Spécificités du C++ - Index


La déclaration d'une fonction ou d'une classe template doit être suffisamment flexible pour être utilisée dans une DLL (bibliothèque de liaison dynamique et partagée) ou un fichier exécutable. La même déclaration de template doit être disponible en importation comme en exportation ou sans modificateur. Pour être complètement flexible, les déclarations de template du fichier en-tête ne doivent pas utiliser les modificateurs __export et __import. Cela permet d'appliquer le modificateur approprié au point d'instanciation selon la manière dont l'instanciation va être utilisée.

Les étapes suivantes illustrent la manière d'exporter et d'importer des templates. Le code source est organisé en trois fichiers. En utilisant le fichier en-tête, du code est généré dans la bibliothèque de liaison dynamique (DLL).

  1. Déclarations de templates exportables/importables
    Le fichier en-tête contient toutes les déclarations de classes et de fonctions template. Une version d'exportation/importation du template peut être instanciée en définissant la macro appropriée au moment de la compilation.
  2. Compilation de templates exportables
    Ecrivez le code source d'une bibliothèque de liaison dynamique. Une fois compilée, la bibliothèque a du code d'export réutilisable pour les templates.
  3. Utilisation d'ImportTemplates
    Il est maintenant possible d'écrire un appel de fonction utilisant des templates. Ce fichier exécutable est lié à la DLL. Seuls les objets non déclarés dans le fichier en-tête qui sont instanciés dans la fonction main provoquent la génération d'un code nouveau par le compilateur. Le code des objets nouvellement instanciés est écrit dans le fichier main.obj.

Instanciation et exportation explicites des membres de templates à partir de classes exportées

Lorsque vous exportez une classe qui contient des fonctions membre de template depuis une DLL ou un package (en utilisant respectivement la directive __declspec(dllexport) ou la macro PACKAGE), ces membres doivent être explicitement instanciés et exportés. Sinon, les consommateurs de la classe exportée obtiendront des erreurs d'externes non résolus concernant le membre de template.

Exemple :

mypackage.h:
#define PACKAGE __declspec(package)
class PACKAGE X
{
public:
  int foo();
  template<typename T>
  int bar(T *p)
  {
    return *p;
  }
};


mypackage.cpp:
#include "mypackage.h"
int X::foo()
{
  return 7;
}

Ce qui précède réside dans un package C++.

L'app suivante invoquant le membre bar obtient un externe non résolu :

myapp.cpp:

#include "mypackage.h"

int g = 6;

int main()
{
  X x;
  x.foo();
  return x.bar(&g);
}
 Error:
 Error: Unresolved external 'int X::bar<int>(int*)' referenced from C:\USERS\ADMIN_000\APPDATA\LOCAL\TEMP\MYAPP-233656.O

Pour résoudre l'erreur, ajoutez la ligne suivante à mypackage.cpp :

template PACKAGE int X::bar<int>(int*);

La ligne ajoutée instancie et exporte explicitement le template de membre utilisé par le source myapp.cpp.