Je sais pourquoi inclure des gardes existants et que Ma question est d'un type différent: p>
Y a-t-il une raison sensible de ne jamais les avoir? Je n'ai pas encore rencontré une situation dans laquelle théoriquement, il y aurait un avantage de ne pas fournir les gardes d'un dossier destiné à être inclus ailleurs. Est-ce que quelqu'un a un exemple où il y a un avantage réel de ne pas les avoir? P>
La raison pour laquelle je me demande - à moi, ils semblent assez redondants, comme vous les utilisez toujours, et que le comportement de #pragma une fois code> n'est pas standard et donc non pris en charge par tous les compilateurs, etc. P>
#pragma une fois code> pourrait aussi bien être appliqué automatiquement à tout. p >
6 Réponses :
J'ai vu des en-têtes qui génèrent du code en fonction des macros définies avant leur inclusion. Dans ce cas, il est parfois voulu de définir ces macros à une (s) valeur (s), inclure l'en-tête, redéfinir les macros et inclure à nouveau.
Tout le monde qui voit telle accepte qu'elle est laide et la mieux évitée, mais parfois (comme si le code dans lesdits en-tête est généré par un autre moyen) c'est le moindre mal de le faire. p>
Autre que cela, je ne peux pas penser à une raison. p>
J'ai rencontré cet usage particulier dans la bibliothèque FFTW (il y a quelque temps, peut-être que cela change maintenant). Un certain nombre de fonctions sont définies de manière à ce qu'ils puissent être créés pour différents types sous-jacents: dans, double, flotteur, etc., vous pouvez donc définir autant de types que nécessaire et indiquez simplement le fichier. Cependant, c'est une bibliothèque C. En C ++, bien sûr, nous utiliserions des modèles ...
@Le_mandrill: En C ++, il est réellement utilisé dans certaines situations où les modèles ne correspondaient pas au problème. En particulier avec la bibliothèque de préprocesseur de boost pour générer automatiquement le même code avec un nombre différent d'arguments, comme dans boost :: lid code> avec 0, 1, 2 ... n Arguments.
@David Rodríguez: Autant que je sache, Boost :: Lié est mis en œuvre en fournissant les modèles appropriés jusqu'à 9 arguments. EDIT: OK J'ai trouvé un endroit où Boost pour éviter la situation code> Retour x code> avec des fonctions avec des arguments de modèle en tant que valeurs de retour (lorsque le type de retour est vide), mais j'ai toujours réussi à résoudre ces éléments Avec une spécialisation de modèle spécifique pour le type void code>. Ils vont la route sans que les gardes incluent, mais il n'est pas nécessaire de redéfinir une macro code> de retour code> afin de résoudre ce problème.
@Mephane: Mon mauvais, je n'ai pas vérifié quelle bibliothèque c'était la bibliothèque et gênait celui de l'autre. Boost :: Signal a une en-tête Signal_Template.hpp incluse du signal # .HPP, où # gammes de 0 à 10. ALORS.HPP, inclut tout signal # .hpp, donc le signal_template.hpp est inclus 11 fois le signal intérieur .HPP
J'ai utilisé la construction multi-include sur des plates-formes embarquées dans lesquelles accéder aux membres de la structure via le pointeur vers la structure était beaucoup moins efficace (plus de 2x le coût) d'accéder aux variables globales. Avoir deux copies de la même pièce de code qui fonctionnent sur des variables globales distinctes du même type de structure était moins chère que d'avoir une copie qui a accepté un pointeur de structure comme argument. Une telle conception serait inefficace sur certaines autres plates-formes, mais elle offrait une économie d'espace importante et des économies d'exécution encore plus importantes par rapport à des approches alternatives plus conventionnelles.
Un autre exemple est dans Xfree86 (au moins dans les années 1990; Je n'ai pas regardé plus récemment). Certains des fichiers DDX ont été compilés pour plusieurs profondeurs de bits en incluant le code source avec des définitions différentes des macros.
Cela peut être un problème si vous avez deux en-têtes dans un projet qui utilisent la même chose incluent la garde, par exemple. Si vous avez deux bibliothèques tierces, et ils ont tous les deux un en-tête qui utilise un symbole de garde comprennent un symbole de garde, tel que __ constantes_h __ code>, vous ne pourrez pas réussir
#include code> en-têtes dans une unité de compilation donnée. Une meilleure solution est
#pragma une fois code>, mais certains compilateurs plus anciens ne supportent pas cela. P>
De plus, #pragma une fois code> n'est pas standard i> b>, et il n'y a aucune garantie La prochaine version de votre compilateur la prendra toujours en charge ou supporte la même chose. sémantique. Pour moi, c'est une très bonne raison de ne pas l'utiliser.
@SBI: True - Comme c'est si souvent le cas, c'est un compromis entre la portabilité et les problèmes tels que celui que je décris ci-dessus. Je suppose que vous pourriez toujours attirer une chapeau de chauver très laid, vous testez la version du compilateur et du compilateur, puis utilisez des gardes ou des #pragma une fois code> en conséquence, mais je ne suis pas sûr que j'aimerais voir que dans chaque en-tête.
Eh bien, si deux incluent les gardes de la collision, la réponse est de changer l'un d'entre eux, de ne pas omettre ...
@Mephane: Ce n'est pas une solution idéale lors de l'utilisation de bibliothèques tierces
Eh bien, vous changez que votre propre collision inclut la garde. Et si les gardes incluent deux bibliothèques tiers entrent en collision ... vous pouvez fournir une enveloppe avec (à l'intérieur de son propre gardien) indéfique le symbole d'enracin et inclut ensuite l'en-tête de tiers incriminé. Mais c'est hors du sujet de toute façon.
@Mephane: Si vous relisez ma réponse, l'exemple que j'ai donné était pour Deux bibliothèques de tiers i> Deux tiers, où chaque bibliothèque tiers utilisait la même chose inclure la protection pour l'un de ses fichiers d'en-tête.
Le problème pour #pragma une fois code> est que si vous avez ces deux fichiers avec les mêmes incluent la protection, et vraisemblablement le même nom de fichier, comment Le compilateur B> décidera s'il s'agit de deux différents fichiers, ou exactement le même fichier sur deux montures de réseau différents? Que faites-vous quand cela fait une erreur?
@Bo: Eh bien, ils ne I> nécessairement i> ont le même nom de fichier, et l'ensemble de l'utilisation de #pragma une fois code> est pour que vous n'ayez pas besoin d'inclure des gardes, mais Oui, je peux voir qu'il pourrait y avoir des problèmes de décider si deux en-têtes apparemment différents sont en réalité une même en-tête accessible via différents chemins.
Supposons que vous ayez une bibliothèque tierce partie et vous ne pouvez pas modifier son code. Supposons maintenant que les fichiers de cette bibliothèque génèrent des avertissements du compilateur. Vous voudrez normalement compiler votre propre code à des niveaux d'alerte élevés, mais cela générerait ainsi un grand ensemble d'avertissements d'utilisation de la bibliothèque. Vous pouvez écrire des en-têtes Disabler / Enabler d'avertissement que vous pourriez ensuite envelopper la bibliothèque tiers, et ils devraient pouvoir être inclus plusieurs fois. P>
Un autre type d'utilisation plus sophistiqué est la construction du préprocesseur de Boost de Boost: http://www.boost.org/doc/libs /1_46_0/libs/preprocessor/doc/index.html P>
Je ne vois pas comment ne pas avoir d'inclure des gardes dans ladite wrapper ferait une différence. Si vous avez déjà inclus l'emballage, les avertissements sont désactivés pour l'en-tête tiers dans que i> incluent déjà, et la deuxième fois que vous inclurez l'enveloppe, il serait capturé par le gardien Inclure et non rien du tout.
@Mephane: Ce sont les en-têtes contenant des pragmas de contrôle d'alerte spécifiques au compilateur qui vont sans incluent les gardes, pas les en-têtes de bibliothèque éclaboussures d'avertissement.
<cassert> <assert.h> "The assert macro is redefined according to the current state of NDEBUG each time that <assert.h> is included."
@sbi a déjà parlé de génération de code, alors laissez-moi donner un exemple.
Dites que vous avez une énumération de nombreux articles et que vous souhaitez générer un tas de fonctions pour chacun de ses éléments. .. p>
Une solution consiste à utiliser cette touche d'inclusion multiple. p> puis les gens utilisent simplement comme suit: p> Que ce soit bien ou pirate est à vous, mais il est clair qu'il est utile de ne pas avoir à ramper à travers toutes les fonctions utilitaires chaque fois qu'une nouvelle valeur est ajoutée à l'énum. P> p>
Et si vous mettez le #define my_enumeration_meta_function code> sur le top myenumeration.td, vous pouvez simplement inclure le deuxième fichier une fois i> et cela pourrait inclure le premier fichier une fois. Votre exemple ressemble à une cyclique arbitraire inclure une dépendance pouvant être évitée facilement. Corrigez-moi si j'ai tort, s'il-vous plait.
@Mephane: Je ne comprends pas comment il y aurait une dépendance cyclique étant donné que "énumération.td" n'inclut rien ... aussi le macro my_enumeration_meta_function code> n'est pas censé être défini dans le fichier d'énumération Comme cela empêcherait son utilisation comme une méta-fonction, elle vaincre donc le but de le définir.
Ah maintenant je le vois. Le deuxième fichier n'est pas un autre en-tête avec le code de réutilisation, mais une implémentation réelle, et chaque implémentation pourrait définir leur propre version de my_enumeration_meta_function code>. Et oui, cela ressemble totalement à un hack. Que ce soit en mesure de faire des choses comme ceci est un avantage réel ou non serait plutôt subjectif, mais je vois la possibilité maintenant.
@Mephane: Je dois admettre que je ne suis pas aussi confortable avec ça. Il est fortement utilisé dans la catégorie LLVM / ClangBase et présente l'avantage de ne pas nécessiter de maintenir un script (dans une autre langue) pour générer ces fonctions. Une orientation appropriée des objets avec des usines et al serait fonctionné ... mais serait plus lente, et LLVM / Clang sont très optimisés à la fois en termes de mémoire et de vitesse, de sorte qu'elles ne respectent pas les hacks aussi longtemps que cela leur profite.
Le problème avec #pragma une fois, et la raison pour laquelle il ne fait pas partie de la norme, est que cela ne fonctionne pas toujours partout. Comment le compilateur sait-il si deux fichiers sont le même fichier ou non, si inclus des chemins différents? P>
Pensez-y, que se passe-t-il si le compilateur fait une erreur et ne parvient pas à inclure un fichier qu'il aurait dû inclus? Que se passe-t-il si cela inclut un fichier deux fois, qu'il ne devrait pas avoir? Comment allez-vous résoudre ce problème? P>
Avec les gardes inclus, le pire qui peut arriver est qu'il faut un peu plus de temps à compiler. P>
EDIT: Découvrez ce fil sur comp.std.c ++ "#pragma une fois en ISO Standard?" P>
http://groups.google.com/group/ comp.std.c ++ / browse_thread / thread / C527240043C8DF92 P>
Je ne demandais spécifiquement pas la différence entre #pragma une fois code> et
#define code> inclure-gardes, mais pour des situations valides dans lesquelles vous souhaitez spécifiquement inclure plusieurs fois un fichier plusieurs fois.
Ok, je pensais que vous avez demandé pourquoi nous n'avons pas #pragma une fois code> partout par défaut. Comme dans la dernière phrase ...
Je demandais plus sur l'effet désiré lui-même; #pragma une fois CODE> est un moyen d'atteindre cet effet, comme cela comprend des gardes-gardes.
Oui, #pragma une fois code> va bien, sauf quand cela ne fonctionne pas. :-) Il n'y a aucun moyen de le faire Toujours B> Toujours B>, donc le comité de langue décidé de pas b> l'inclure dans la langue. Si cela fonctionne pour vous, avec le compilateur et le système d'exploitation et la configuration du réseau que vous avez, bien!