60 votes

Quel est l'avantage des virgules dans une instruction conditionnelle?

Nous pouvons écrire une déclaration if comme

 if (a == 5, b == 6, ... , thisMustBeTrue)
 

et seule la dernière condition devrait être satisfiable pour entrer dans le corps if .

pourquoi est-ce permis?

67voto

Jon Jagger Points 546

La modification de votre exemple légèrement, suppose que c'était ce

if ( a = f(5), b = f(6), ... , thisMustBeTrue(a, b) )

(note de l' = au lieu de ==). Dans ce cas, les virgules garantir un ordre de gauche à droite de l'évaluation. En contraste, avec cette

if ( thisMustBeTrue(f(5), f(6)) )

vous ne savez pas si f(5) est appelée avant ou après l' f(6).

Plus formellement, des virgules, qui vous permettent d'écrire une séquence d'expressions (a,b,c) de la même façon, vous pouvez utiliser ; d'écrire une suite d'instructions, a; b; c;. Et juste comme un ; crée un point de séquence (à la fin de la pleine expression) aussi une virgule. Seule la séquence de points régissent l'ordre d'évaluation, voir ce post.

Mais bien sûr, dans ce cas, vous fait écrire ce

a = f(5);
b = f(6);    
if ( thisMustBeTrue(a, b) )

Alors, quand est, séparés par des virgules séquence d'expressions préférable à un ; séparés séquence d'instructions? Presque jamais, je dirais. Peut-être dans une macro lorsque vous voulez le côté droit, en remplacement d'une seule expression.

44voto

MikeMB Points 5827

En bref: Même si il est légal de le faire, il n'a généralement pas de sens d'utiliser l'opérateur virgule en l'état partie d' if ou while déclaration (EDIT: Même si ce dernier peut parfois être utile comme user5534870 explique dans sa réponse).

Une version plus élaborée explication: Outre sa fonction syntaxique (par exemple, éléments de séparation dans l'initialiseur de listes, les déclarations de variables ou des appels de fonction/déclarations), en C et C++, l' , peut également être sur un opérateur, comme par exemple, +, et il peut donc être utilisé partout où une expression est autorisée (en C++, vous pouvez même la surcharge).
La différence de la plupart des autres opérateurs, c'est que - bien que les deux côtés sont évaluées - il ne pas combiner les sorties de la gauche et la droite expressions en aucune façon, mais renvoie simplement le droit.
Il a été introduit, parce que quelqu'un (probablement Dennis Ritchie) a décidé, pour quelque raison que C une syntaxe pour écrire deux (ou plus) sans rapport avec les expressions à une position où d'ordinaire pouvait écrire une expression unique.

Maintenant, la condition d'une if déclaration est (entre autres) un tel endroit et, par conséquent, vous pouvez également utiliser l' , opérateur y - si cela a du sens de le faire ou pas est une question entièrement différente! En particulier - et les différents provenant, par exemple, les appels de fonction ou de déclarations de variables - la virgule n'a pas de signification particulière, de sorte qu'il fait, ce qu'il a toujours fait: Il évalue les expressions à gauche et à droite, mais seulement renvoie le résultat de la droite, qui est ensuite utilisé par l' if déclaration.

Les deux seuls points que je pense maintenant, où à l'aide de la (non surchargé) ,-opérateur de sens que sont:

  1. Si vous voulez incrémenter plusieurs itérateurs dans la tête d'un for boucle:

    for ( ... ; ... ; ++i1, ++i2){
        *i2=*i1;
    }
    
  2. Si vous voulez évaluer plus d'une expression en C++11 constexpr fonction.

Pour répéter une fois de plus: à l'Aide de l'opérateur virgule en if ou while énoncé dans la façon dont vous l'a montré dans votre exemple - n'est-ce pas quelque chose d'intelligent à faire. Il est juste un autre exemple où le langage de syntaxe de C et C++ vous permettent d'écrire du code, qui ne se comportent pas de la manière que le premier coup d'œil - attendez. Il ya beaucoup plus....

15voto

user5534870 Points 149

Pour un if déclaration, il n'y a pas de véritable point de mettre quelque chose dans une virgule expression plutôt qu'à l'extérieur.

Pour un while déclaration, mettre une virgule expression de la condition exécute la première partie , soit lors de l'entrée de la boucle, ou si la boucle. Qui ne peuvent pas facilement être reproduit sans duplication de code.

Alors, comment un s do...while déclaration? Il nous ont seulement à vous soucier de la boucle elle-même, non? Il s'avère que même pas ici une virgule expression peut être remplacer en toute sécurité par le déplacement de la première partie dans la boucle.

Pour une chose, destructeurs pour les variables dans le corps de la boucle n'auront pas déjà été exécuté, alors qui peut faire une différence. Pour un autre, tout continue déclaration à l'intérieur de la boucle atteindra la première partie de la virgule expression uniquement lorsqu'il est en effet dans l'état plutôt que dans le corps de la boucle.

10voto

BeyelerStudios Points 688

Il n'y a aucun avantage : l'opérateur virgule est simplement une expression avec le type de la dernière expression dans sa liste d'expressions et une instruction if évalue une expression booléenne.

 if(<expr>) { ... }
 with type of <expr> boolean
 

C'est un opérateur étrange, mais il n'y a pas de magie - sauf qu'il confond les listes d'expressions avec les listes d'arguments dans les appels de fonctions.

 foo(<args>)
 with <args> := [<expr>[, <expr>]*]
 

Notez que dans la liste des arguments, la virgule se lie davantage à la séparation des arguments.

7voto

frozenkoi Points 1899

Ce qui suit est un peu exagéré, selon la façon dont rusé, vous pourriez être.

Considérons une situation où une fonction retourne une valeur en modifiant un paramètre passé par référence ou par pointeur (peut-être d'un mal conçu de la bibliothèque, ou pour s'assurer que cette valeur n'est pas ignorée par ne pas être affecté après son retour, peu importe).

void calculateValue(FooType &result) {/*...*/}

Alors, comment utilisez-vous les instructions conditionnelles qui dépendent result?

Vous pouvez déclarer la variable qui va être modifié, puis vérifier avec un si:

FooType result;
calculateValue(result);
if (result.isBared()) {
    //...
}

Ce pourrait être réduit à

FooType result;
if (calculateValue(result) , result.isBared()) {
    //...
}

Ce qui n'est pas vraiment la peine. Cependant, pour while boucles il pourrait y avoir quelques petits avantages. Si calculateValue doit-on/peut être appelé jusqu'à ce que le résultat n'est plus bar'd, nous aurions quelque chose comme:

FooType result;
calculateValue(result);  //[1] Duplicated code, see [2]
while (result.isBared()) {
    //... possibly many lines
    //separating the two places where result is modified and tested

    //How do you prevent someone coming after you and adds a `continue`
    //here which prevents result to be updated in the and of the loop?

    calculateValue(result); //[2] Duplicated code, see [1]
}

et pourrait être condensé:

FooType result;
while (calculateValue(result) , result.isBared()) {
    //all your (possibly numerous) code lines go here
}

De cette façon, le code pour mettre à jour result est en un seul endroit, et est près de la ligne de où ses conditions sont vérifiées.

peut-être sans rapport avec: une Autre raison pour laquelle les variables pourrait être mis à jour via le paramètre passant, c'est que la fonction doit retourner le code d'erreur en plus de modifier/retourne la valeur calculée. Dans ce cas:

ErrorType fallibleCalculation(FooType &result) {/*...*/}

alors

FooType result;
ErrorType error;

while (error = fallibleCalculation(result) , (Success==error && result.isBared())) {
    //...
}

mais comme il est noté dans les commentaires, vous pouvez le faire sans la virgule de trop:

FooType result;
ErrorType error;

while (Success == fallibleCalculation(result) && result.isBared()) {
    //...
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X