C/C++/macro modèle de blackmagic pour générer nom unique
Les Macros sont très bien.
Les modèles sont beaux.
Assez bien ce que ça fonctionne bien.
L'exemple est OpenGL; mais la technique est le C++ spécifiques et s'appuie sur aucune connaissance de l'OpenGL.
Problème précis:
J'ai envie d'une expression E; où je n'ai pas à indiquer un nom unique, à tel point qu'un constructeur est appelé où E est défini, et un destructeur est appelé lorsque le bloc E est dans les extrémités.
Par exemple, pensez à:
class GlTranslate {
GLTranslate(float x, float y, float z); {
glPushMatrix();
glTranslatef(x, y, z);
}
~GlTranslate() { glPopMatrix(); }
};
Solution manuelle:
{
GlTranslate foo(1.0, 0.0, 0.0); //I had to give it a name
.....
} //auto popmatrix
Maintenant, j'ai ce non seulement pour glTranslate, mais beaucoup d'autres PushAttrib/PopAttrib appels trop. Je préférerais ne pas avoir à venir avec un nom unique pour chaque var. Est-il une astuce impliquant des macros modèles ... ou quelque chose d'autre qui va automatiquement créer une variable qui est constructeur est appelé au moment de la définition; et destructeur appelé à la fin du bloc?
Merci!
- Je ne vois pas pourquoi la pensée d'un nom unique est plus que de l'exécution de certains complexes appel de macro.
- Pour ce que ça vaut, j'ai essayé un régime similaire à once upon a time. J'ai trouvé qu'il était plus facile de simplement faire une certaine forme de
Transformation
classe qui avaitpush/pop
comme vous avez, avec les fonctions de membres qui font appels à traduire, etc. Vous n'avez plus qu'une seule classe, et vous êtes également à seulement pousser quand vous en avez besoin. - Je pense que la réponse est LIGNE: ou COMPTEUR 🙂
- ah, bon point, parce que j'ai à payer un supplément de glPushMatrix() pour tous les non-autochtones de traduire dans mon régime
- Peut-être:
GlTranslate(1.0, 0.0, 0.0), work_to_be_done_in_block(...);
- Pourriez-vous développer ce que?
- Je suggère (pas tout à fait au sérieux) pour transformer les blocs d'une seule virgule expression. Autant que je sache, temporaires sont détruits après la pleine expression est évaluée (après work_to_be_done appel...) => pas besoin de donner un nom à l'instance, pas même un seul 😉
- haha voir ci-dessous pour l'opérateur virgule ruse xD
Vous devez vous connecter pour publier un commentaire.
Si votre compilateur prend en charge
__COUNTER__
(il n'a probablement), vous pourriez essayer:Pour
_trans
. Ces noms sont réservées uniquement dans l'espace de noms global ou dans l'espace de noms std. Des noms qui sont réservés partout dans le monde sont ceux qui ressemblent à des_Trans
ou__trans
.__LINE__
a aussi l'avantage que vous pouvez faire référence à la variable de nouveau dans votre macro. Avec__COUNTER__
, il va incrément de nouveau.Je ne voudrais pas le faire personnellement, mais juste de venir avec des noms uniques. Mais si vous voulez le faire, une façon est d'utiliser une combinaison de
if
etfor
:Vous pouvez l'utiliser comme
Chacun de ces noms sont dans des domaines distincts et ne pas entrer en conflit. L'intérieur des noms de masquer l'extérieur noms. Les expressions dans le
if
etfor
boucles sont constants et doit être facilement optimisé par le compilateur.Si vous avez vraiment envie de passer à une expression, vous pouvez utiliser le ScopedGuard truc (voir Le plus Important
const
), mais il aura besoin d'un peu plus de travail pour l'écrire. Mais le côté sympa, c'est, que nous pouvons nous débarrasser de lafor
boucle, et laissez notre objet d'évaluer lafalse
:Ensuite, vous fournissez la bonne
enter
etleave
fonctions:Maintenant, vous pouvez l'écrire entièrement, sans un nom du côté de l'utilisateur:
Si vous souhaitez passer plusieurs expressions à la fois, c'est un peu plus délicat, mais vous pouvez écrire une expression modèle qui agit sur
operator,
de recueillir toutes les expressions dans unscont
.Vous avez besoin d'hériter de la RAII objet de
scoped_obj<Class>
comme le montre l'exemple suivantL'ensemble de ces impliquent pas de fonctions virtuelles, et les fonctions concernées sont transparentes pour le compilateur. En fait, avec ce qui précède
GLTranslate
modifié pour ajouter un entier à une variable globale, et avant de quitter le soustraire à nouveau, et la ci-dessous définiGLTranslateE
, j'ai fait un test:En fait, GCC au niveau d'optimisation
-O2
sorties ceci:Je n'aurais pas cru qu'il optimisé tout à fait bien!
bool _c_ = false
se débarrasser des avertissements du compilateur ou de quelque chose? (Justefalse
) EDIT: Derp, jamais l'esprit, je ne vois pourquoi. Quelle astuce. :]BOOST_FOREACH
macro 🙂Trans toOrigin(-x, -y, -z);
au lieu de simplement écrireTrans(-x, -y, -z)
ouTrans foo(-x, -y, -z);
qui n'est pas de transmettre le véritable but de la transformaion.FOR(Trans t(a, b, c)) foo();
par exemple. Mais vraiment, la première solution est moins ma préférée. Si je voulais écrire, pas de noms, j'opte pour la dernière solution présentée.if(sbase const& _b_ = make_scont((E))) ;
vous voudrez peut-être remplacer l'instruction vide avecuse_variable(_b_);
de sorte que le compilateur ne se plaint pas de_b_
être utilisées (pour ceux -Werror les amateurs). Jolie astuce bien, j'ai commencé à l'utiliser dans le code de production.Je pense qu'il est maintenant possible de faire quelque chose comme ceci:
ensuite dans le code
Évidemment, C++11 est nécessaire
std::function
à un modèle pour s'assurer de l'in-lining, c'est possible 🙂La manière canonique tel que décrit dans l'une réponse est d'utiliser une expression lambda comme le bloc, en C++, vous pouvez facilement écrire une fonction de modèle
et de l'utiliser comme
mais la raison la plus courante pour vouloir un mécanisme pour éviter la définition des noms dans votre champ le long de fonctions /méthodes de faire beaucoup de choses. Vous avez peut-être essayer un moderne de la programmation orientée objet /code propre style d'inspiration avec de très courtes méthodes /fonctions pour un changement si ce genre de problème vous importune garde