10
votes

Comment faire fonctionner des paramètres d'indicateur? (C ++)

Comment pourrais-je faire une fonction avec des drapeaux comme la manière dont Windows 'Creewindow (... Style | Style, ...), Par exemple, une fonction Creeenum:

int CreateNum(flag flags) //???
{
    int num = 0;
    if(flags == GREATER_THAN_TEN)
        num = 11;
    if(flags == EVEN && ((num % 2) == 1)
        num++;
    else if(flags == ODD && ((num % 2) == 0)
        num++;
    return num;
}
//called like this
int Number = CreateNum(GREATER_THAN_TEN | EVEN);


0 commentaires

6 Réponses :


32
votes

Vous pouvez définir une énumération spécifiant des valeurs "à une seule bit" (notez que la struct enfermante n'agit ici qu'en tant que contexte de dénomination, de sorte que vous puissiez écrire, par exemple, myFlags :: Même code>):

int CreateNum(int flags){
    if (flags & MyFlags::EVEN){
        // do something...
    }
}

void main(){
    CreateNum(MyFlags::EVEN | MyFlags::ODD);
}


9 commentaires

Peut-être que vous pourriez faire votre énumé plus longtemps, pour préciser que cela doit être des pouvoirs de deux?


+1. En côté, il est inutile de comparer le drapeau avec "== myFlags :: Même", car il sera égal à zéro ou non à zéro, ce qui est automatiquement destiné à bool plutôt gentiment.


Je ne pense pas qu'il soit possible de passer deux (ou plus) drapeaux à l'aide de | opérateur si vous utilisez cette approche.


Pourquoi ne pouviez-vous pas réussir plusieurs drapeaux de cette façon? On dirait que tu pouvais


Parce que même | Impair sera converti en Int, et Creeenum () accepte MyFlags :: Valeur. Je ne compilerai pas à imo, mais je pourrais me tromper.


Danadam a raison: le paramètre ne devrait pas être "myFlags :: Value", car une combinaison de drapeaux n'est pas une valeur myFlags :: Valeur (par exemple, même | impair 3, ce qui n'est pas un membre d'enum valide). Vous pouvez toujours lancer la combinaison, mais c'est sale.


Petit conseil: Je trouve plus gentil d'écrire des valeurs ENUM comme suit: 1 << 0, 1 << 1, 1 << 2, etc., donc je ne fais pas d'erreurs stupides écrivant la puissance de deux littéralement. (Je fais rarement, mais je me sens très stupide quand cela se produit, alors j'essaie de l'éviter).


@Marcus: Il me semble qu'il y a la même probabilité de faire une erreur avec les 2 notations, ne pensez-vous pas :)?


@Danadam - J'aurais fait quelque chose comme Par défaut étrange, il ne serait donc pas possible de dire même | Immédiué, juste même si vous voulez que le nombre soit même, et rien pour impair.



6
votes

Vous pouvez utiliser const int comme ceci: xxx

et lorsque vous l'utilisez: xxx

Bien sûr, vous pouvez mettre un drapeau ou plus dans vos drapeaux à l'aide de l'opérateur | .


3 commentaires

Changer #define flag1 0x0001 à const int flag1 = 0x0001;


D'accord avec Alexey ... n'utilisez pas de macros pour cela.


const int peut être remplacé par consexpr int aujourd'hui.



0
votes

Vous avez tes tests. Ce que vous voulez, c'est quelque chose comme (drapeaux et même) , où même est un entier avec un seul jeu de bits (1, 2, 4, 8, 16 - une puissance de 2). (L'entier peut être un int ou un énorme. Vous pourriez avoir une macro, mais ce n'est généralement pas une bonne idée.)

Vous pouvez utiliser la notation que vous avez énumérée, en surcharge indicateurs :: opérateur == (flagvalue f) , mais c'est une mauvaise idée.


0 commentaires

1
votes

Utiliser des pouvoirs de deux comme des constantes individuelles, comme xxx

et vous utilisez le logique et l'opérateur "&" pour tester, comme xxx


0 commentaires

0
votes
enum flags {
    EVEN =        0x0100,
    ODD =         0x0200,
    BELOW_TEN =   0x0400,
    ABOVETEN =    0x0800,
    HUNDRED =     0x1000,
    MASK =        0xff00
};

void some_func(int id_and_flags)
{
    int the_id = id_and_flags & ~MASK;
    int flags = id_and_flags & MASK;
    if ((flags & EVEN) && (the_id % 2) == 1)
        ++the_id;
    if ((flags & ODD) && (the_id % 2) == 0)
        ++the_id;
    // etc
}
Illustrates masking of bit fields too which can be useful when you just need to bolt on a simplistic bit of extra functionality without adding any extra data structure.

0 commentaires

13
votes

J'ai suscité la réponse d'Orsogufo, mais j'ai toujours aimé faire ce qui suit pour définir les valeurs: xxx

<< est l'opérateur de changement de vitesse. L'incrémentation du côté droit vous permet de générer des masques de bits séquentiels en déplaçant le 1 sur, un peu à la fois. Cela a les mêmes valeurs pour les drapeaux nus, mais se lit plus facile à mes yeux et le rend évident si vous sautez ou de la dupliquer une valeur.

J'aime aussi combiner des combinaisons de drapeau communes lorsque cela est approprié.


1 commentaires

Grande solution. L'introduction de changements logiques facilite la mise à jour beaucoup plus facile à lire.