Newsgroup: it.comp.lang.c++
Titolo: Passaggio di argomenti enum con operatore "|"

Ciao!
Sono abbastanza niubbio con il c++. Ho una domanda da porvi. Spesso
vedo che vengono passati a funzioni un argomento con multipli enum
(penso) divisi dall'operatore logico "|".
Faccio un esempio:
MessageBox( NULL, "Errore", "Accidenti", MB_OK | MB_ICONERROR |
MB_TASKMODAL);
Il terzo argomento contiene appunto tre parametri che descrivono lo
stile del MessageBox. Visto che è una cosa comune e pare molto utile,
vorrei sapere come viene "interpretato" il terzo argomento nella
specificazione della funzione.
Grazie e scusate se la domanda è banale,
Marco

MB_TASKMODAL);
I valori specificati non appartengono a un enum ma sono valori
costanti fissi.  E' un semplice "or" bitwise.
In generale, se hai:
A = 1 (in binario: 001)
B = 2 (in binario: 010)
C = 4 (in binario: 100)
ognuna delle quali rappresenta un'opzione specifica per una
determinata operazione, puoi "comporre" più opzioni in un unico valore
numerico, compattando quindi la rappresentazione:
A | B = 001 | 010 = 011 (i bit a 1 sono solo quelli di A e B).
B | C = 010 | 100 = 110 (i bit a 1 sono solo quelli di B e C).
A | B | C = 001 | 010 | 100 = 111 (tutti e tre i bit sono a 1).
...
...
Quand'è così, un | (or) corrisponde a un semplice +.

ramar wrote:



Dipende un po del tipo del parametro, ma la semantica del baso è
sempre la stessa: si divisa una variabile in campi, con un campo
diverso per ogni parametro. Molte volte sono campi booleani,
qualcosa di genere:
    enum ControlStates
    {
        //  ...
        CS_XXX_ON  = 0x40 ,
        CS_XXX_OFF = 0x00 ,
        //  ...
    } ;
Cioè: ON a un valore con un solo bit a uno, et OFF un valore di
zero. Per provare, nella funzione, si e OFF o ON:
    if ( (argument & CS_XXX_ON) != 0 ) {
        //  è attiva...
    }
(Attenti pore: la stessa cosa non funzionne con CS_XXX_OFF!)
A volte, si vuole più di bits. Da essempio:
    CS_XXX_IN      = 0x00,
    CS_XXX_OUT     = 0x10,
    CS_XXX_BIDIR   = 0x20,
    CS_XXX_DIRMASK = 0x30,      // si usa solo interna
Qui, puoi provare con un switch:
    switch ( argument & CS_XXX_DIRMASK ) {
    case CS_XXX_IN :
        //  ...
        break ;
    case CS_XXX_OUT :
        //  ...
        break ;
    case CS_XXX_BIDIR :
        //  ...
        break ;
    default:
        assert( 0 ) ;
        abort() ;
    }
(Per un buon essempio, vedi il fmtflags di std::ios.)
Al nivello dell'implementazione, ci son due alternativi: nel
classico, venendo di C, la funzionne prende un "unsigned int", o
qualcosa di simile. L'enum non serve che per definire le
costanti. È la soluzione la più facile, ma permette errore comme
passare 42 come parametro. In C++ moderne, è più frequante di
definire anche gli operatori | et & sul l'enum, cosi:
    inline ControlStates
    operator|( ControlStates lhs, ControlStates rhs )
    {
        return ControlStates( (unsigned)lhs | (unsigned)rhs ) );
    }
    //  lo stesso per &, ed eventuellemente anche per ^, |=, &=
    //  et ^=
Allora, il tipo di parametro può essere anche ControlStates, che
limita le possibilità di errore. (Se vai al sito mio,
kanze.james.neuf.fr
, nel codice, c'è un programma chi genera
automaticalemente tutti gli operatori "bitwise" per un enum.
Vedi il pagine di man a
http://kanze.james.neuf.fr/doc/man/man1/enumgen.man.html
.)
--
James Kanze (Gabi Software)              email: 
kanze...@neuf.fr
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, 
+33 (0)1 30 23 00 34