Ne support du C++ compiler-compteurs de temps?
Dans le but d'introspection, j'ai parfois voulu attribuer automatiquement des numéros de série de types, ou quelque chose de similaire.
Malheureusement, le modèle de la métaprogrammation est essentiellement un langage fonctionnel, et en tant que tel manque de variables globales ou modifiables etat qui mettrait en place un tel compteur.
Ou est-il?
Exemple de code à la demande:
#include <iostream>
int const a = counter_read;
counter_inc;
counter_inc;
counter_inc;
counter_inc;
counter_inc;
int const b = counter_read;
int main() {
std::cout << a << ' ' << b << '\n'; //print "0 5"
counter_inc_t();
counter_inc_t();
counter_inc_t();
std::cout << counter_read << '\n'; //print "8"
struct {
counter_inc_t d1;
char x[ counter_read ];
counter_inc_t d2;
char y[ counter_read ];
} ls;
std::cout << sizeof ls.x << ' ' << sizeof ls.y << '\n'; //print "9 10"
}
- pouvez-vous donner un court exemple pour faire la démonstration de ce qu'est exactement la question ?
- il n'est pas possible d'utiliser
X<__LINE__>
? qui fournira un numéro unique (peut-être pas de numéro de série) toujours dans le fichier donné. - Cela ne fonctionne pas à travers plusieurs en-têtes, et de ne pas renvoyer le même résultat à plusieurs reprises lors de l'unicité n'est pas souhaitée. Le modèle de solution est plus puissant. Voir la réponse.
- Connexes: C++ construction qui se comporte comme le COMPTEUR macro.
InformationsquelleAutor Potatoswatter | 2011-05-29
Vous devez vous connecter pour publier un commentaire.
Eh bien... oui, le modèle de la métaprogrammation manque d'effets secondaires car il est destiné. J'ai été induit en erreur par un bug dans les anciennes versions de GCC et un peu moins clair, le libellé de la Norme de croire que toutes ces fonctionnalités sont possibles.
Cependant, au moins l'espace de noms-la portée de la fonctionnalité peut être réalisé avec peu de modèles à tous. La fonction de recherche peut extraire numérique de l'état de l'ensemble des fonctions déclarées, comme illustré ci-dessous.
Bibliothèque de code:
Démonstration rapide (voir courir):
C++11 Mise À Jour
Ici est une version mise à jour à l'aide de C++11
constexpr
en place desizeof
.http://ideone.com/yp19oo
Les déclarations doivent être mis à l'intérieur d'un espace de noms, et tous les noms utilisés dans les macros à l'exception des
counter_crumb
doivent être qualifiés. Lecounter_crumb
modèle est disponible via l'ADL association avec leconstant_index
type.La
COUNTER_LINK_NAMESPACE
macro peut être utilisée pour incrémenter un compteur dans le champ d'application de plusieurs espaces de noms.cn<N>
peuvent être rembourrés au compilateur de discrétion. Doncsizeof( cn<N> )
peut être n'importe quelle valeur >= N. a Besoin d'utilisersizeof( cn<N>::data )
.__COUNTER__
) atténue l'inclusion de l'ordre d'émission. Si la numérotation des fichiers d'en-tête est le but, alors l'utilisateur doit être conscient de la cohérence à l'échelle de Cus.decltype
mot-clé.)counter_read()
etcounter_inc
ont besoin de quelques explications, en particulier l'utilisation decn<>
,seen
et de l'opération au niveau du bit(x+1) & ~x
,etc. ils ont l'air tellement alambiquées!Je crois que les deux MSVC et GCC soutenir un
__COUNTER__
préprocesseur jeton qui a un monotone croissante de la valeur substitué à sa place.duodecilliotonically
, si j'obtiens mon préfixes droit... 😛Je pensais à résoudre ce problème depuis un certain temps, et ont abouti à un très court de solution propre. Au moins j'ai le mérite upvote pour essayer. :))
Suivants code de la bibliothèque réalise des fonctionnalités au niveau de l'espace de noms. c'est à dire, je réussis à mettre en œuvre
counter_read
etcounter_inc
; mais pas lecounter_inc_t
(qui est incrémenté à l'intérieur de la fonction, cartemplate
classes ne sont pas autorisés à l'intérieur de la fonction)Cette technique utilise modèle de méta-programmation et tire profit de l'
__LINE__
macro.Voir le résultat pour le code de votre réponse.
Vous pouvez utiliser
BOOST_PP_COUNTER
de Boost.Préprocesseur.Avantage: il fonctionne même pour les macros
Inconvénient: il n'est qu'un "contre-nature" pour l'ensemble du programme, mais le mécanisme peut être réimplémentée dédié compteurs
Car le partage est attentionné et j'ai passé quelques heures à bidouiller avec l'exemple de base cette côté offre, je vais les poster ma solution.
La version lié à l'article a deux inconvénients majeurs. Le nombre maximum qu'elle peut compter trop est très faible, en raison de max profondeur de récursion (généralement de l'ordre de 256). Et le temps qu'il faut pour compiler dès qu'un nombre de plus d'une centaine a été atteint est énorme.
Par la mise en œuvre de la recherche binaire pour détecter si un drapeau pour un compteur a déjà été définie ou pas, il est possible d'augmenter massivement le compte maximum (contrôlable par MAX_DEPTH) et également d'améliorer les temps de compilation en même temps. =)
Exemple d'utilisation:
Entièrement code de travail avec exemple à la fin: (Sauf pour le bruit. Voir les commentaires.)
adl_flag
a été défini ne fonctionne pas pour clang. (Celui-ci:class = char[noexcept( adl_flag(flag<N>()) ) ? +1 : -1]
) Si vous pouvez en trouver un qui renvoie correctement un type, que siadl_flag(flag<N>)
a déjà été défini, cela fonctionnera.Voici une autre variante de mise en œuvre. https://stackoverflow.com/a/6174263/1190123 est probablement mieux, mais même après avoir manuellement par l'intermédiaire d'un couple incréments sur le papier, je n'ai pas encore tout à fait comprendre les maths/filtrage.
Il utilise constexpr fonction de la récursivité pour compter le nombre de non-modèle déclaré
Highest
fonctions.__COUNTER__
est utilisé comme une question de génération mécanisme pour empêcher de nouvelles déclarations deHighest
de faire de l'auto de récursivité.Ce ne compile sur clang pour moi (3.3). Je ne suis pas sûr que c'est compatible, mais j'ai bon espoir. g++ 4.8 échoue en raison d'une fonctionnalité n'est pas implémentée (en fonction de l'erreur). Intel compilateur 13 échoue également, en raison d'un constexpr bug.
256 niveau de contre
Le nombre maximal par contre est de 250 (CounterLimit). CounterLimit peut être augmenté de 256 à moins que vous mettre en œuvre la LCount trucs ci-dessous.
Mise en œuvre
Tests
Sortie
250 * 250 niveau de contre
Si vous voulez des valeurs plus élevées que 256, je pense que vous pouvez combiner les compteurs. J'ai fait 250 * 250 (bien que je n'ai pas vraiment fait de test de comptage 2 dernières). CounterLimit doit être abaissé à environ 250 pour le compilateur moment de la compilation de la récursivité des limites. Juste pour remarque, cela a pris beaucoup plus de temps à compiler pour moi.
Mise en œuvre
Tests
__VA_ARGS__
et variadic macros pour passer,
comme une macro argument, ce qui éviteCOMMA
.__VA_ARGS__
conseil! Je ne veux pas critiquer votre réponse, même si vous l'a expliqué, je ne suis pas sûr que j'ai la condition des facultés mentales. Si vous n'avez ajouter un peu plus d'explication, je suis à la lire attentivement.CounterLimit
récurrences dansGetCount
et3 * CounterLimit
dans GetLCount.__COUNTER__
ne devait changer la fonction de la visibilité et de la force du modèle reinstantiation. Je viens de vérifier le bien et CounterLimit peut être 250 avec pas de questions, donc je pense que l'origine, j'avais mal évalué la récursivité chose.__COUNTER__
est incrémenté à chaque accès, si je suis en train de lire correctement, vous serez à court d'instanciations juste en y accédant. Je n'ai pas testé. De façon plus critique, cela peut aller à l'encontre de l'ODR car deux différentes unités de traduction avec les mêmes en-têtes à l'aide deGetCount
différemment aura techniquement différentes définitions, même si chaque utilisation renvoie la même valeur dans chaque TU. Je pense qu'il est possible de l'utiliser en toute légalité avec affectation judicieuse pourconstexpr
variables, mais la suite de la lettre de l'ODR peut être délicat.C++ permet de compiler des compteurs de temps (c'est à dire sans
__COUNTER__
,__LINE__
ou d'autres approches proposées ici plus tôt) ainsi que de l'allocation et de la définition interne int ID unique pour chaque modèle. Voir v1 solution pour le compteur mis en œuvre avec le modèle metaprograming en utilisant le chaînage attribué Id et v2 pour le deuxième cas d'utilisation. Ces deux solutions sont des réponses pour "Comment puis-je générer dense unique Id de type au moment de la compilation?". Mais la tâche est une condition essentielle à propos de l'ID de l'allocateur.