Déclaration de spécialisation de membre de classe de modèle

Lorsque je spécialise une fonction / constante membre (statique) dans une classe de modèle, je suis confus quant à la destination de la déclaration.

Voici un exemple de ce que je dois faire – directement à partir de la référence d’ IBM sur la spécialisation des modèles :

=== Exemple de spécialisation de membre IBM ===

template class X { public: static T v; static void f(T); }; template T X::v = 0; template void X::f(T arg) { v = arg; } template char* X::v = "Hello"; template void X::f(float arg) { v = arg * 2; } int main() { X a, b; X c; cf(10); // X::v now set to 20 } 

La question est, comment puis-je diviser cela en fichiers en-tête / cpp? L’implémentation générique est évidemment dans l’en-tête, mais qu’en est-il de la spécialisation?

Cela ne peut pas aller dans le fichier d’en-tête, parce que c’est concret, ce qui conduit à plusieurs définitions. Mais s’il se trouve dans le fichier .cpp, le code qui appelle X :: f () est-il conscient de la spécialisation ou peut-il s’appuyer sur le générique X :: f ()?

Jusqu’à présent, je n’ai que la spécialisation dans le fichier .cpp, sans déclaration dans l’en-tête. Je n’ai pas de difficulté à comstackr ni même à exécuter mon code (sur gcc, je ne me souviens pas de la version pour le moment), et il se comporte comme prévu – en reconnaissant la spécialisation. Mais A) je ne suis pas sûr que ce soit correct, et j’aimerais savoir ce que c’est, et B) ma documentation Doxygen est débile et très trompeuse (plus à ce sujet dans une minute plus tard).

Ce qui me semble le plus naturel serait quelque chose comme ceci: déclarer la spécialisation dans l’en-tête et la définir dans le fichier .cpp:

=== XClass.hpp ===

 #ifndef XCLASS_HPP #define XCLASS_HPP template class X { public: static T v; static void f(T); }; template T X::v = 0; template void X::f(T arg) { v = arg; } /* declaration of specialized functions */ template char* X::v; template void X::f(float arg); #endif 

=== XClass.cpp ===

 #include  /* concrete implementation of specialized functions */ template char* X::v = "Hello"; template void X::f(float arg) { v = arg * 2; } 

… mais je ne sais pas si cela est correct. Des idées?

Habituellement, vous définissez simplement les spécialisations dans l’en-tête, comme le dit dirkgently.

Vous pouvez définir des spécialisations dans des unités de traduction distinctes, mais si vous êtes inquiet au sujet des temps de compilation ou du gonflement du code:

 // xh: template struct X { void f() {} } // declare specialization X::f() to exist somewhere: template<> void X::f(); 

 // translation unit with definition for X::f(): #include "xh" template<> void X::f() { // ... } 

Alors oui, votre approche semble bien aller. Notez que vous ne pouvez le faire qu’avec des spécialisations complètes . Il est donc souvent impossible de le faire.

Pour plus de détails, voir par exemple la FAQ des modèles Comeaus .

Mettez-les tous dans un fichier hpp . Faites inline sorte que les spécialisations et tout ce que vous définissez en dehors de la classe soit inline – cela prendra en charge plusieurs définitions.

Pour répondre à l’une de vos questions: le is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?

Si le compilateur voit une définition qui correspond à ses exigences, il l’utilisera. Sinon, il va générer des appels de fonction normaux.

Dans votre premier extrait de code, vous fournissez une définition générique pour X::f(T arg) , afin que le compilateur l’instancie pour tout T exception de float .

Si vous omettez la définition générique, le compilateur générera des appels à, disons, X::f(double) et l’éditeur de liens ira chercher la définition qui pourrait se terminer par une erreur de l’éditeur de liens.

Pour résumer: Vous pouvez tout avoir dans les en-têtes car, en tant que modèles, vous n’obtiendrez pas plusieurs définitions. Si vous n’avez que des déclarations, vous aurez besoin de définitions ailleurs pour que l’éditeur de liens puisse les retrouver plus tard.