En C et C++ il est habituel de séparer la déclaration d'une fonction et sa
définition dans deux fichier séparés: l'entête contenant la déclaration (fichier
.h
ou .hh
) et le code source proprement dit contenant sa
définition (fichier .c
ou .cpp
). Lorsque l'on veut faire la
même chose avec une fonction utilisant un template, on obtient une erreur du
type "undefined reference to" lors de la première utilisation de la fonction
dans le code.
Un exemple
Par exemple supposons la fonction addition
qui retourne la somme de deux nombre de même type:
Tout d'abord le fichier d'entete (addition.hh
):
template<typename Type> Type addition(Type a, Type b);
Le code source de la fonction (addition.cc
):
template<typename Type> Type addition(Type a, Type b)
{
return a + b;
}
Une portion de code utilisant cette fonction (main.cc
):
#include "addition.hh"
void main()
{
int a = 3;
int b = 2;
int c =0;
c = addition(a, b)
}
Bien que le code semble correct, la création de lien va échouer avec l'erreur:
/tmp/ccEpROXj.o(.text+0x17c): In function `main':
: undefined reference to `addition(int, int)'
Le pourquoi
Il y a différentes raisons pour lesquels cette erreur apparait. Il s'agit principalement du fait qu'un template n'est pas une fonction mais un modèle utilisé pour générer la fonction. Lorsqu'il est utilisé dans un programme pour générer une fonction, la définition dois être connue et non seulement la déclaration.
Comment s'en sortir
Il existe plusieurs solutions à ce problème.
Insertion de la définition dans le fichier d'entête
La première consiste à inclure la définition dans le fichier d'entête. Pour cela
il suffit de fusionner les deux fichiers entête et code source dans un seul
fichier ou alors inclure le fichier du code source via une commande
include
de preprocessing à la fin du fichier d'entête. Cette solution
est la plus simple mais le résultat n'est pas forcément très propre. En effet
certains compilateur peuvent entrainer une augmentation dramatique de la taille
de l'exécutable.
Ajout d'une spécialisation du template
FIXME: A confirmer
On peut également ajouter les déclaration des spécialisations que l'on veut utiliser dans le fichier source de la fonction.
Par exemple en reprenant le fichier source de notre fonction addition, on spécifier les déclarations pour les types int
, float
et double
:
template<typename Type>
Type addition(Type a, Type b)
{
return a + b;
}
template int addition<int>(int, int);
template float addition<float>(float, float);
template double addition<double>(double, double);
Utilisation du mot clef export
FIXME