2009-10-19 8 views
9

Wie könnte ich eine Funktion mit Fahnen wie, wie Windows' Create (... style | Stil, ...), zum Beispiel einer createnum Funktion:Wie mache ich Funktionen mit Flagparametern? (C++)

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); 

Ist dies möglich, und Wenn das so ist, wie?

Antwort

27

Sie können eine ENUM definieren „einzelnes Bit“ Werte spezifiziert (beachten Sie, dass die umschließende Struktur hier nur als Namenskontext handelt, so dass Sie schreiben können zB MyFlags::EVEN):

struct MyFlags{ 
    enum Value{ 
     EVEN       = 0x01, 
     ODD       = 0x02, 
     ANOTHER_FLAG     = 0x04, 
     YET_ANOTHER_FLAG    = 0x08, 
     SOMETHING_ELSE     = 0x10, 
     SOMETHING_COMPLETELY_DIFFERENT = 0x20 
    }; 
}; 

und dann verwenden, wie folgt aus:

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

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

oder einfach so:

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

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

Sie könnte auch ganzzahlige Konstanten deklarieren, aber die Enum ist meiner Meinung nach klarer.

Hinweis: Ich habe den Beitrag aktualisiert, um einige Kommentare zu berücksichtigen, danke!

+5

Vielleicht könnten Sie Ihre Enum länger machen, um klar zu machen, es muss Potenzen von zwei sein? – KeatsPeeks

+1

+1. Nebenbei, es ist unnötig, das Flag mit "== MyFlags :: EVEN" zu vergleichen, da es entweder Null oder nicht Null ist, was automatisch dazu führt, dass es sich ziemlich gut boolt. – rmeador

+0

Ich glaube nicht, dass es möglich ist, zwei (oder mehr) Flags mit | zu übergeben wenn Sie diesen Ansatz verwenden. – danadam

5

können Sie const int wie folgt verwenden:

const int FLAG1 = 0x0001; 
const int FLAG2 = 0x0010; 
const int FLAG3 = 0x0100; 
// ... 

Und wenn Sie es verwenden:

int CreateNum(int flags) 
{ 
    if(flags & FLAG1) 
     // FLAG1 is present 

    if(flags & FLAG2) 
     // FLAG2 is present 

    // ... 
} 

Natürlich können Sie einen oder mehrere Flagge in Ihre Fahnen mit dem | Betreiber setzen können.

+4

Ändern Sie '#define FLAG1 0x0001' in' const int FLAG1 = 0x0001; ' –

+0

Vereinbaren Sie mit Alexey ... Verwenden Sie keine Makros dafür. – Bill

+0

Ja, Sie haben Recht, es ist besser. Ich habe es geändert. –

0

Sie haben Ihre Tests falsch. Was Sie wollen, ist etwas wie (flags & EVEN), wobei EVEN eine ganze Zahl mit einem einzelnen Bit gesetzt ist (1, 2, 4, 8, 16 - etwas Potenz von 2). (Die Ganzzahl kann ein Int oder eine Enum sein. Sie könnten ein Makro haben, aber das ist im Allgemeinen keine gute Idee.)

Sie können die Notation verwenden, die Sie aufgelistet haben, indem Sie flags::operator==(flagvalue f) überladen, aber es ist eine schlechte Idee.

1

Verwenden Zweierpotenzen wie die einzelnen Konstanten, wie

enum Flags { EVEN = 0x1, ODD = 0x2, GREATER_TEN = 0x4 }; 

und Sie den logischen und Operator '&' für die Prüfung, wie

if(flags & GREATER_THAN_TEN) 
    num = 11; 
if((flags & EVEN) && (num % 2) == 1) 
    num++; 
else if ((flags & ODD) && (num % 2) == 0) 
    num++; 
return num; 
0
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 
} 

Illustriert Maskierung von Bitfeldern Auch das kann nützlich sein, wenn Sie nur ein simples bisschen zusätzlicher Funktionalität benötigen, ohne eine zusätzliche Datenstruktur hinzuzufügen.

10

ich upvoted orsogufo Antwort, aber ich habe immer gerne die für die Festlegung der Werte wie folgt vorgehen:

enum Value{ 
    EVEN       = (1<<0), 
    ODD       = (1<<2),   
    ANOTHER_FLAG     = (1<<3),   
    YET_ANOTHER_FLAG    = (1<<4),   
    SOMETHING_ELSE     = (1<<5),   
    SOMETHING_COMPLETELY_DIFFERENT = (1<<6), 

    ANOTHER_EVEN     = EVEN|ANOTHER_FLAG 
}; 

< < der Verschiebungs-Operator ist. Durch Inkrementieren der rechten Seite können Sie sequentielle Bitmasken erzeugen, indem Sie die 1 um jeweils ein Bit verschieben. Dies hat die gleichen Werte für die blanken Flags, liest sich aber leichter für meine Augen und macht es offensichtlich, wenn Sie einen Wert überspringen oder duplizieren.

Ich mag auch einige gemeinsame Flag Kombinationen kombinieren, wenn angemessen.

+0

+1 von mir; Ich auch, wie definieren "gemeinsame Kombinationen" :) –