2009-09-29 6 views
3

Autrefois, pour utiliser une classe de modèle en C++, les implémentations devaient être dans le fichier d'en-tête ou # incluses dans le fichier d'en-tête en bas.Modèles C++: les fichiers d'en-tête sont-ils toujours brisés?

Je n'ai pas utilisé de modèles C++ depuis quelques années; Je ai juste commencé à les utiliser à nouveau et observé que ce comportement semble pour persister. Est-ce toujours le cas? Ou les compilateurs sont-ils assez intelligents maintenant pour avoir l'implémentation séparée de l'interface?

+0

Même avec l'exportation, vous ne pourrez toujours pas vous passer de la source (sous quelque forme que ce soit). Les docs EDG disent: "Les fichiers .et informent seulement le frontend sur l'emplacement des définitions de templates exportés, ils ne contiennent pas réellement ces définitions.Les sources contenant les définitions de template exportées doivent donc être disponibles au moment de l'instanciation (habituellement , quand la prélocation est faite). * En particulier, la facilité d'exportation n'est pas un mécanisme pour éviter la publication des définitions de modèles sous forme de source. * "(insistez par moi) –

+0

@litb: C'est irritant. Mais merci pour votre réponse. –

+0

Je n'ai pas vraiment implémenté de compilateur donc je ne suis pas en mesure de le dire, mais je crois que les créateurs d'EDG :) –

Répondre

2

Pour séparer l'implémentation de la déclaration, la norme vous oblige à utiliser le mot-clé export. Pour autant que je sache, il n'y a qu'un seul compilateur qui sait comment le gérer: Comeau. Cependant, C++ 0x inclura un mécanisme qui indique au compilateur de ne pas instancier certaines spécialisations automatiquement (modèles externes). Donc, si vous voulez réduire le temps de compilation, vous pourrez le faire en instanciant explicitement certaines spécialisations dans une unité de compilation et en les déclarant dans l'en-tête comme extern.

2

Vous faites référence à des modèles exportés (en utilisant le mot-clé export), qui semblent être pris en charge uniquement par Comeau C++ (selon this section du C++ FAQ Lite). Une technique courante pour conserver l'interface dépourvue de code de mise en œuvre consiste à placer les définitions de fonctions en ligne dans un en-tête de "mise en œuvre" distinct qui peut être inclus à la fin de l'en-tête de déclaration.

+0

Pour être honnête, je ne suis pas à la recherche d'exportation. Je cherchais simplement l'en-tête pour ne pas avoir à inclure les implémentations du template dedans (comme les autres fonctionnalités du langage?). –

1

L'exportation est prise en charge uniquement par le frontend EDG, commercialement disponible uniquement dans le compilateur Comeau autant que je sache. L'exportation n'élimine pas la nécessité d'une divulgation de source, ni ne réduit les dépendances de compilation, alors qu'elle nécessite un effort considérable de la part des constructeurs de compilateurs. Donc, Herb Sutter lui-même a demandé aux constructeurs de compilateurs d '«oublier» l'exportation. Comme l'investissement en temps serait mieux dépensé ailleurs ... je ne pense pas que l'exportation sera jamais mise en œuvre par d'autres compilateurs après qu'ils aient vu combien de temps cela a pris, et combien peu a été gagné. Le document s'appelle "Pourquoi on ne peut pas se permettre d'exporter", il est listé sur Sutters blog mais pas de pdf là-bas (un google rapide devrait le faire monter), il a six ans maintenant, je suppose qu'ils ont tous écouté et jamais ennuyé :)

Beaucoup de gens utilisent deux fichiers d'en-tête (par exemple .hpp et .ipp), l'un avec seulement la déclaration, et l'autre avec les définitions, alors il suffit d'en inclure un dans l'autre.

foo.hpp

#ifndef MY_TEMPLATES_HPP 
#define MY_TEMPLATES_HPP 

template< class T > 
void foo(T & t); 

#include "foo.ipp" 
#endif 

foo.ipp

#ifdef MY_TEMPLATES_IPP 
    nonsense here, that will generate compiler error 
#else 
#define MY_TEMPLATES_IPP 

template< class T > 
void foo(T & t) { 
    ... // long function 
} 

#endif 

Ce que des gains un peu de clarté, bien sûr, rien ne change vraiment par rapport à tout simplement inline tout dans un seul fichier d'en-tête.

+0

Trouvé le pdf auquel vous faites référence: http://ra.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1426.pdf, daté de mars 2003 –

+0

@Matthieu M.: le PDF semble cassé. Mieux vaut obtenir l'original: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1426.pdf – paercebal

+0

@paercebal: Merci! –

3

Techniquement, ils n'ont pas besoin de pour être dans le fichier d'en-tête. Un exemple de cette utilisation est lorsque vous avez une classe de modèle avec un ensemble fixe de versions (disons pour les arguments sake char et wchar_t). Ensuite, vous pouvez mettre toutes les delcarations de méthode dans un fichier source et instancier explicitement ces deux versions.Cela a la sécurité que les autres ne peuvent pas istanciate le modèle pour les types pour lesquels il n'était pas destiné à être utilisé.

// X.h 
template<typename T> 
class X 
{ 
    // DECLARATION ONLY OF STUFF 
    public: 
     X(T const& t); 
    private: 
     T m_t; 
}; 

// X.cpp 
#include "X.h" 

// DEFINTION OF STUFF 
template<typename T> 
X<T>::X(T const& t) 
    :m_t(t) 
{} 

// INSTANCIATE The versions you want. 
template class X<char>; 
template class X<wchar_t>; 


// Main.cpp 
#include "X.h" 

int main() 
{ 
    X<chat> x1('a'); 
    X<wchar_t> x2(L'A'); 
    // X<int>  x3(5); // Uncomment for a linker failure. 
} 

personnes ne peuvent pas simplement supposant inclure directement x.cpp (car il n'est pas fourni par la distribution), alors d'autres ne peuvent pas utiliser X < int> ou X < float> etc. Mais les classes sont entièrement abovr défini.

J'ai également vu cette technique utilisée pour réduire le temps de compilation. Comme chaque unité de compilation ne reproduit pas la même version de X, nous obtenons seulement la définition à un endroit (donc un coût de compilation). Le downsize à ceci est que vous devez instancier manuellement chaque version de X que vous utilisez.

+0

C'est assez chouette, bien qu'il ne fasse pas ce dont j'ai besoin. Je m'en souviendrai cependant. –

0

GCC effectue une longue phase de collecte, sauf si vous instanciez explicitement tous les modèles. VC++ semble faire face, mais je préfère quand même éviter cette étape et dans les cas où je sais comment le template va être utilisé, ce qui est généralement le cas pour les applications, pas tellement pour les bibliothèques, je mets les définitions de templates dans un fichier séparé. Cela rend également le code plus lisible en rendant les déclarations moins encombrées de détails d'implémentation.

Questions connexes