Dans mon travail quotidien, j'écris généralement mon code comme celui-ci.
int ret = 0; ret = func1(); if(ret != 0) { return ret; } ret = func2(); if(ret != 0) { return ret; }
Mais cela signifie que je dois compléter beaucoup de "if (ret! = 0) {return ret;}", y a-t-il une implémentation plus élégante en C ++ pour terminer le saut de fonction? À propos, nous ne sommes pas autorisés à utiliser l'exception.
5 Réponses :
Le code affiché semble être logiquement équivalent à:
int ret; if ((ret=func1()) || (ret=func2())) return ret;
Effectuez autant d'appels de fonctions supplémentaires que vous le souhaitez, de manière évidente.
C ++, en tant que descendant de C, a la même méthode abrégée pour l'affectation et la vérification ensemble:
#define RNZ(x) if ((ret = x) != 0) return ret int ret; RNZ(func1()); RNZ(func2());
Cela fonctionne car a = something
est lui-même une expression dont la valeur est a
.
Si vous vouliez taper encore moins de code pour chaque appel et vérification, vous pourriez opter pour une macro, mais c'est probablement exagéré (je ne le ferais pas moi-même), mais je le montrerai juste au cas où vous seriez intéressé :
int ret; if ((ret = func1()) != 0) return ret; if ((ret = func2()) != 0) return ret;
C ++ 17 et les versions ultérieures autorisent également les instructions de sélection avec un initialiseur , vous pouvez donc même avoir if (auto ret = func(); ret != 0)
si cela vous plaît plus, ou si vous devez vérifier une partie de ret
place
int foo(){ return Status{} .invoke(func1) .invoke(func2, 0) .invoke(func3, 3) .value(); }
Une autre possibilité consiste à effectuer une boucle for range
sur un ensemble de fonctions:
#include <iostream> class Obj { public: int func1() { std::cout << "in func1\n"; return 0; } int func2() { std::cout << "in func2\n"; return 0; } int func3() { std::cout << "in func3\n"; return 3; } int foo () { for (auto ff: {&func1, &func2, &func3}) { int ret; if ((ret=(this->*ff)()) != 0) { return ret; } } return 0; } }; int main() { Obj var; std::cout << var.foo() << "\n"; }
Production:
#include <iostream> int func1() { std::cout << "in func1\n"; return 0; } int func2() { std::cout << "in func2\n"; return 0; } int func3() { std::cout << "in func3\n"; return 3; } int foo () { for (auto& ff: {func1, func2, func3}) { int ret; if ((ret=ff()) != 0) { return ret; } } return 0; } int main() { std::cout << foo() << "\n"; }
Code:
in func1 in func2 in func3 3
Dans un commentaire, vous avez posé la question de savoir comment le faire fonctionner avec les fonctions membres. Cela semble plus délicat, en particulier parce que le compilateur a du mal à deviner le type correct de la liste_initialisation. C'est une façon de le résoudre.
for (auto& ff: {func1, func2, func3}) {
Je n'ai jamais pensé à utiliser des listes d'initialisation pour les fonctions. Que c'est intelligent!
cela a l'air génial! mais si func1 、 func2 et func3 sont des fonctions membres, comment pouvons-nous le faire fonctionner?
J'ai essayé de proposer une solution, voir la réponse mise à jour. Veuillez noter que normalement une nouvelle question doit correspondre à un nouveau message!
En utilisant une expression fold et une instruction if
avec initialisation, vous pouvez écrire le modèle de fonction variadique suivant qui prend un nombre arbitraire de pointeurs vers ces fonctions comme arguments de modèle non-type:
if (int ret = overall_func<func1, func2, func3>(); ret) return ret;
De cette façon, vous factorisez tous les appels à ces fonctions, les affectations de valeurs de retour correspondantes et leurs contrôles individuels. Finalement, cela se résume à une seule vérification et une seule déclaration de return
:
template<int(...Funcs)()> // equivalent to template<int(*...Funcs)()> int overall_func() { if (int ret; (... || (ret = Funcs()))) return ret; return 0; }
Ceci est quel que soit le nombre de fonctions à appeler.
Ce n'est pas plus élégant, mais plus compact le serait
if ((ret = func1()) != 0) { return ret; }