J'ai une classe appelée Writer
qui a une fonction writeVector
comme ceci:
void Drawer::writeVector(vector<T> vec, bool index=true)
{
for (unsigned int i = 0; i < vec.size(); i++) {
if (index) {
cout << i << "\t";
}
cout << vec[i] << "\n";
}
}
J'essaie de ne pas avoir de code en double, tout en me souciant des performances. Dans la fonction, je if (index)
vérifie à chaque tour de ma for
boucle, même si le résultat est toujours le même. C'est contre "s'inquiéter de la performance".
Je pourrais facilement éviter cela en plaçant le chèque en dehors de ma for
boucle. Cependant, j'obtiendrai beaucoup de code en double:
void Drawer::writeVector(...)
{
if (index) {
for (...) {
cout << i << "\t" << vec[i] << "\n";
}
}
else {
for (...) {
cout << vec[i] << "\n";
}
}
}
Ce sont donc deux «mauvaises» solutions pour moi. Ce que j'ai pensé, ce sont deux fonctions privées, l'une d'elles sort de l'index et appelle l'autre. L'autre dépasse seulement la valeur. Cependant, je ne peux pas comprendre comment l'utiliser avec mon programme, j'aurais quand même besoin de la if
vérification pour voir lequel appeler ...
Selon le problème, le polymorphisme semble être une solution correcte. Mais je ne vois pas comment l'utiliser ici. Quelle serait la meilleure façon de résoudre ce genre de problème?
Ce n'est pas un vrai programme, je suis juste intéressé à apprendre comment ce genre de problème devrait être résolu.
la source
Réponses:
Passez le corps de la boucle en tant que foncteur. Il est intégré au moment de la compilation, aucune pénalité de performance.
L'idée de transmettre ce qui varie est omniprésente dans la bibliothèque standard C ++. Cela s'appelle le modèle de stratégie.
Si vous êtes autorisé à utiliser C ++ 11, vous pouvez faire quelque chose comme ceci:
Ce code n'est pas parfait mais vous voyez l'idée.
Dans l'ancien C ++ 98, cela ressemble à ceci:
Encore une fois, le code est loin d'être parfait mais il vous donne l'idée.
la source
for(int i=0;i<100;i++){cout<<"Thank you!"<<endl;}
: D C'est le genre de solution que je cherchais, ça marche comme un charme :) Vous pourriez l'améliorer avec quelques commentaires (j'ai eu du mal à la comprendre au début), mais je l'ai donc pas de problème :)cout << e << "\n";
), il y aurait encore une certaine duplication de code.Si tel est effectivement le cas, le prédicteur de branche n'aura aucun problème à prédire le résultat (constant). En tant que tel, cela n'entraînera qu'une légère surcharge pour les erreurs de prédiction dans les premières itérations. Il n'y a rien à craindre en termes de performances
Dans ce cas, je préconise de garder le test à l'intérieur de la boucle pour plus de clarté.
la source
std::cout
do utile )Pour développer la réponse d'Ali, qui est parfaitement correcte mais duplique quand même du code (une partie du corps de la boucle, c'est malheureusement difficilement évitable lors de l'utilisation du modèle de stratégie) ...
Certes, dans ce cas particulier, la duplication de code n'est pas beaucoup, mais il existe un moyen de la réduire encore plus, ce qui est pratique si le corps de la fonction est plus grand que quelques instructions .
La clé est d'utiliser la capacité du compilateur à effectuer une élimination constante de pliage / code mort . Nous pouvons le faire en mappant manuellement la valeur d'exécution de
index
à une valeur au moment de la compilation (facile à faire lorsqu'il n'y a qu'un nombre limité de cas - deux dans ce cas) et en utilisant un argument de modèle non-type qui est connu à la compilation -temps:De cette façon, nous nous retrouvons avec du code compilé qui est équivalent à votre deuxième exemple de code (externe
if
/ internefor
) mais sans dupliquer le code nous-mêmes. Maintenant, nous pouvons rendre la version du modèlewriteVector
aussi compliquée que nous le voulons, il y aura toujours un seul morceau de code à maintenir.Notez comment la version du modèle (qui prend une constante de compilation sous la forme d'un argument de modèle non-type) et la version non-modèle (qui prend une variable d'exécution comme argument de fonction) sont surchargées. Cela vous permet de choisir la version la plus pertinente en fonction de vos besoins, ayant une syntaxe assez similaire et facile à retenir dans les deux cas:
la source
doWriteVector
directement mais je suis d'accord que le nom était malheureux. Je viens de le changer pour avoir deuxwriteVector
fonctions surchargées (un modèle, l'autre une fonction régulière) afin que le résultat soit plus homogène. Merci pour la suggestion. ;)Dans la plupart des cas, votre code est déjà bon pour les performances et la lisibilité. Un bon compilateur est capable de détecter les invariants de boucle et d'effectuer les optimisations appropriées. Prenons l'exemple suivant qui est très proche de votre code:
J'utilise la ligne de commande suivante pour le compiler:
Ensuite, vidons l'assemblage:
L'assemblage de résultat de
write_vector
est:Nous pouvons voir qu'au début de la fonction, nous vérifions la valeur et sautons à l'une des deux boucles possibles:
Bien sûr, cela ne fonctionne que si un compilateur est capable de détecter qu'une condition est un invariant réel. Habituellement, cela fonctionne parfaitement pour les indicateurs et les fonctions en ligne simples. Mais si la condition est «complexe», envisagez d'utiliser des approches d'autres réponses.
la source