Bonjour,

Premièrement, j’utilise le compilateur gcc/g++ version 4.5.0 sur Linux.

En explorant le monde merveilleux des modèles (template), je suis tombé sur un os :
on peut définir des fonctions modèles sans arguments (de fonction) et les appeler comme ceci :

Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Déclaration
template<typename _Type>
void Function();
 
// Définition
template<typename _Type>
void Function()
{
   std::cout << "void Function<_Type>()\n";
}
 
// Instanciation explicite
template
void Function<int>();
 
// Appel
int main()
{
   Function<int>();
   return 0;
}

Par contre, j’ai remarqué qu’on pouvait déclarer, définir et instancier explicitement des constructeurs modèles sans arguments (de fonction) de la même manière, mais je suis incapable de les appeler :

Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// Définition d’une classe
class TClass
{
public:
   template<typename _Type>
   TClass();
};
 
// Définition du constructeur modèle
template<typename _Type>
TClass::TClass()
{
   std::cout << "TClass::TClass<_Type>()\n";
}
 
// Instanciation explicite
template
TClass::TClass<int>(); // Ceci est légal
 
// Utilisation
int main()
{
   TClass Class1; // Illégal, le constructeur par défaut n’est pas généré à
                  // cause de la présence du constructeur modèle (ça me semble
                  // normal)
 
   TClass Class2<int>; // Illégal, le '<' est pris pour un opérateur
                       // 'inférieur à'
 
   TClass Class3(TClass()); // Légal, le constructeur par copie par défaut est
                            // utilisé, ce qui me semble normal, mais le
                            // constructeur par défaut est généré ici alors
                            // qu’il ne l’est pas pour Class1, bizarre !!!
 
   TClass Class4(TClass<int>()); // Illégal, 'TClass<int>' est pris pour le
                                 // nom d’une classe modèle
 
   TClass Class5(TClass::TClass<int>()); // Illégal, un constructeur ne peut
                                         // pas être appelé directement
 
   return 0;
}

Pour info, voici les messages d’erreur renvoyés par g++ :
Pour Class1 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
Test.cpp:25:11: error: no matching function for call to ‘TClass::TClass()’
Test.cpp:5:1: note: candidate is: TClass::TClass(const TClass&)
Pour Class2 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
Test.cpp:29:17: error: expected initializer before ‘<’ token
Pour Class4 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
Test.cpp:37:18: error: ‘TClass’ is not a template
Pour Class5 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
Test.cpp:40:38: error: cannot call constructor ‘TClass::TClass’ directly
Test.cpp:40:38: error:   for a function-style cast, remove the redundant ‘::TClass’
Test.cpp:40:38: error: no matching function for call to ‘TClass::TClass()’
Test.cpp:5:1: note: candidate is: TClass::TClass(const TClass&)
Notez que :
  • J’ai essayer de ne laisser qu’une seule de ces 5 déclarations à la fois et j’ai bien les mêmes messages d’erreur.
  • Lorsque je ne laisse que Class3, que je compile et que j’exécute, c’est bien le constructeur généré par défaut que s’exécute, pas le constructeur modèle avec un paramètre quelconque (pas de sortie sur la sortie standard).
  • Lorsque je mets la déclaration de Class1 après celle de Class3, le constructeur par défaut n’est toujours pas généré pour Class1.
  • J’ai bien compris quelques subtilités des modèles, comme le besoin du mot clé template dans certains cas pour appeler une fonction modèle sans arguments (de fonction), du genre de ce qui est expliqué sur la FAQ de comeau.
    J’ai donc essayé de rajouter ce mot clé à différents endroits, mais rien n’est légal.


Bref, je dois passer à côté de quelque chose, car il me semble bizarre qu’on puisse déclarer, définir et instancier explicitement une fonction modèle qu’on ne peut pas appeler.

  1. Quelqu’un sait comment appeler ce constructeur modèle ?
  2. Est-ce que le comportement de g++ est conforme à la norme ?
  3. Est-ce que d’autre compilateurs acceptent une de ces syntaxes d’appel (je n’en ai pas sous la main) ?
  4. Est-ce que la génération du constructeur par défaut dans un cas et pas dans l’autre (Class1 et Class3) est correct ou est-ce un bug de g++ ?


PS : ceci est une question purement technique, je n’ai pas d’exemple d’utilisation pratique en vue, c’est par pure curiosité que je la pose.