J'utilise la bibliothèque de Regex de Boost et je trouve que la détermination de la détermination du fait que la correspondance nommée est trouvée, puis en utilisant ces informations est un peu gênant. Pour détecter une correspondance nommée, j'aimerais faire cela: Si cela fonctionnerait, ce serait génial. Le scopage serait limité au corps du Si, la mémoire peut être utilisée efficacement et il semble assez propre. Malheureusement, cela ne fonctionne pas comme vous ne pouvez pas définir une variable dans une liste. : ( p> Cela aurait pu être une possibilité: p> mais match_t est une référence de const donc ce n'est pas assignable. (TL; DR Je ne sais pas ce que le type sous-jacent est et que je ne veux généralement pas vraiment savoir que je préférerais une solution plus générique que je pouvais utiliser à l'extérieur de cet exemple de regex. Même STD :: Déplacer () a été utilisé autour de quoi [...] cela devient encore plus verbose et que la documentation ne dit pas qu'il utilise déplacer la sémantique de Sub_Match. Tout cela est discuté bien sûr en raison de la raison donnée dans la première phrase de ce paragraphe.) I> P> Une autre option est de faire est-ce: p> que je n'aime pas en raison d'une nicheur profonde d'accolades. P> Peut-être abuser d'une structure de boucle avec pause code> S à la fin de chaque si code> Corps comme ceci: p> #define IF(declare, cond) do{{declare;if(cond){
#define ELSE_IF(declare, cond) break;}}{declare; if(cond){
#define ELSE break;}}{{
#define END_IF break;}}}while(0);
if(regex_search(str.cbegin(), str.cend(), what, re, flags))
{
IF(match_t type1 = what["type1"], type1.matched)
{
// do stuff with type1
}
ELSE_IF(match_t type2 = what["type2"], type2.matched)
{
// do stuff with type2
}
// ...
ELSE_IF(match_t typeN = what["typeN"], typeN.matched)
{
// do stuff with typeN
}
END_IF
}
3 Réponses :
Vous pouvez faire quelque chose comme ceci (note que ce code n'est pas testé sur un compilateur)
// create a map between match types and actions
std::map<std::string, std::function<match_t>> actions;
actions["type1"] = [&](match_t type) {...};
// iterate through the actions map and check each match type
for(auto kvp : actions)
{
match_t type = what[kvp.first];
if(type.matched)
{
// do stuff with this result
kvp.second(type);
}
}
Hmmm, intéressant. Vous avez oublié la pause à la fin de votre corps si. Les autres problèmes potentiels sont 1. Vous ne pouvez pas définir qui doit être testé en premier (bien que cela puisse être fait à l'aide d'un vecteur d'un tuple). Et 2. Déplace le code du point d'exécution. Mais en utilisant une lambda comme celle-ci est définitivement intéressante. Pourrait également être fait avec une fonction pleine ponctuelle. +1 pour l'ingéniosité. :)
Quelles sont les opinions des gens de la lisibilité de cela? Une action devrait être assez courte. Pas plus de 10 lignes.
Vous pouvez remplacer la carte avec une liste ou un autre conteneur de séquence afin que vous puissiez contrôler l'ordre de l'évaluation des correspondances.
Oui, j'ai mentionné que dans mon premier commentaire. Bien que je l'ai dit comme un vecteur au lieu d'un conteneur de séquence générique.
Vous pouvez écrire un wrap de et ensuite: p> < Pré> xxx pré> pour des points supplémentaires Vous pouvez également surcharger match_t code> avec une surcharge de opérateur bool code>: opérateur -> code>: p>
IMO, des déclarations telles que celles si (BMATCH Type1 = Que ["type1"]) code> ne sont pas très lisibles et je préfère les éviter.
Il est généralement recommandé d'éviter tout Dans votre cas, vous devez utiliser une boucle. P> Votre deuxième exemple: P> si code> s - ils rendent le code plus difficile à lire. S'il y ait nuls si, il devrait probablement remplacer par un appel de fonction. const char *types[] = {"type1", "type2", "typeN", 0};
for(const char **cur = types; *cur; cur++){
found = what[*cur];
if (found.matched){
//initiate robot uprising
break;
}
}
J'aimerai certainement cela car il échoue facilement, est propre et facile à utiliser une table de saut de pointeur de fonction avec elle. Je pense que nous avons un gagnant! :) Bien que l'OMI, un style d'itérateur standard aurait dû être utilisé au lieu d'utiliser une nulle à la fin de la matrice.
Oh, et votre syntaxe est bien éteinte.
Adrian: "La syntaxe est une voie"? Vous voulez dire "{à la fin de la ligne" ou autre chose?
Vous savez quoi, ce n'est peut-être pas. Il y a plusieurs changements syntaxiques dans C ++ 11. Je viens de passer à C ++ 11 et de ce que je sais de C ++, l'initialisation du pointeur que vous avez utilisée n'est pas valide. Est-ce nouveau à C ++ 11? Je suis plus habitué à Const Char * Types [] = {"Type1", "Type2", "Typen", 0}; Code>.
@Adrian: whoops. C'était une faute de frappe (j'ai posté le code sans compiler). En fait, deux d'entre eux. Bon travail remarquant le problème. J'utilise C ++ 03 standard pour le moment, au fait.
Oh. Bon à savoir que je ne vais pas fou ni trop loin derrière la courbe. ;) Même si j'aime ça, je pense que j'aime toujours ma version macro meilleure pour la petite N. Je suis toujours sur la clôture avec elle.
@Adrian: Macros a du sens lorsque vous faites quelque chose de très répétitif / fastidieux - par exemple, si vous devez dérouler manuellement la boucle, etc. Ou si vous faites des choses qui ne peuvent pas être faites avec des modèles (Opérateur de filtre) Votre dernier exemple cache la déclaration de contrôle de flux mais prétend être si, qui (IMO) n'est pas une très bonne chose. Les macros comme ceci ressemblent à une magie noire et pourraient sérieusement confondre le mainteneur. Si j'utilisais une macro dans la boucle, j'utiliserais Multiline Macro (lisibilité), je le définirais dans la boucle, je ne cacherais pas la boucle et je ne ferais pas la macros avant la fin de la boucle.
Si les déclarations sont des déclarations de contrôle de flux i>. La seule différence avec mon macro si code> et la langue si code> est que la macro-one autorise la déclaration d'un objet variable, puis effectuer une opération sur cet objet pour une décision. La seule chose à propos de cette macro si code> est que ce n'est pas standard, il peut donc faire gratter quelqu'un de gratter la tête si elle n'est pas documentée. Une fois compris, il est assez évident que ce qui se passe, et même s'il n'est pas documenté (que je ne recommande pas), il est toujours assez évident quelle est l'intention.
Votre point sur la boucle cachée est intéressant cependant. Il faudrait être documenté que vous ne pouviez pas utiliser un Break code> ou Continuer code> de cette structure de contrôle, car il a détourné la structure de la boucle pour atteindre ses objectifs et résultera dans un comportement inattendu. Cela ou avoir la boucle exposée comme vous l'avez suggéré, mais cela ajouterait au bruit ... Meh haussement d'épaules i>
Notez que
si (foo = bar) code> n'est pas le même quesi (FOO == bar) code> en C ++, le code ne fait probablement pas ce que vous voulez. Aussi, je recommande vivement à l'utilisation de macros pour "supprimer de la malbouffe" comme dans votre dernier exemple. Il ne supprime pas "Junk" mais fait le code incompréhensible.@DAMON: Oui, je sais que = n'est pas la même chose que ==. Le code fait exactement ce que je veux, de limiter la portée, de réduire le bruit et la réutilisation de l'espace de pile (si le compilateur l'optimise). Je suis en quelque sorte d'accord avec vous RE: les macros, mais cela réduit les excès de bruit aussi longtemps que vous savez ce que les macros sont pour, ce qui peut rendre les choses plus claires. Mais ymmv. Donc, je suppose que vous préférez le 2ème avec le
do {} alors que (0); code> Sans les macros?Pas sûr, j'écrirais probablement la toute première version (déclarant les variables dans l'externe
si code> portée, de sorte qu'il compile), car c'est la version la moins obscopée, à mon avis. Mais à la fin de la journée, cela revient au goût personnel. Et, je mettrais des deux parenthèses autour des missions à l'intérieur desi code> pour faire explicite que ceux-ci ne sont pas accidentels (avec des avertissements appropriés activés, c'est ce par ex. GCC suggère de faire, aussi).@Damon: le 1er 1ère? Ou le 3ème sur 5? Je demande cela depuis que le 1er 1ère ne fonctionne pas, et il n'est pas possible de pré-déclarer les variables sans l'affecter une valeur car le type est une référence de const.
Quel est l'obstacle à déclarer (et à affecter, car ils sont des références) les trois comme la première chose dans le bloc ci-joint par
si (regex_search (...)) code>? Cela devrait fonctionner bien, ne devrait-il pas? Dans le pire des cas, il initialise 2 variables en vain, mais en moyenne, ce sera juste bon, et c'est un code lisible :)Il s'agit d'une liste de N types tels que si j'avais une structure de commutation / cas avec N cas. Bien que j'adresse un cas concret, je voudrais une solution générique. Avoir n variables déclaré après le
si (Regex_search (...)) CODE> est inutile car il déclare des variables N-1 en vain et déplace les variables à l'écart de l'emplacement où ils sont utilisés.Alors pourquoi ne pas considérer pas i> utiliser des références de const, donc le code Snippet 2, qui est très propre et sympa compilera. Cela copiera quelques correspondances à la pile, mais donc quoi. Sauf 10 000 matchs, vous ne pouvez pas vous en soucier moins. Si vous avez, dites, 5-10 matchs, alors vous inquiétez des frais généraux de la copie, c'est le cas typique de citant Tony Hoare. De plus, les chances sont le compilateur suffisamment intelligent pour élier la copie de toute façon.