2009-10-05 7 views
3

est-il possible de définir plusieurs opérateurs de sortie pour une énumération? Je veux utiliser cettePlusieurs opérateurs de sortie?

std::ostream& operator<< (std::ostream& os, my_enum e); 

opérateur (1) imprimer un texte lisible par l'homme et (2) le convertir en un code pour le stockage dans une base de données.

Merci

Répondre

4

Créer des emballages qui retournent un objet au lieu de ostream & qui se chargera de l'impression. Dans votre cas, il s'opposera à l'impression d'une valeur lisible par l'utilisateur et à l'objet d'impression du code de la base de données. Voici un exemple approximatif qui imprime une forme lisible par un humain et une forme entière. ostream_enum_wrapper_human classe avec son opérateur < < est utilisé pour l'impression de forme lisible par l'homme, classe ostream_enum_wrapper_int avec son < < est utilisé pour l'impression de code entier. Pour passer de ostream & à wrapper, l'opérateur < < (ostream &, wrappertag) est utilisé, qui enveloppe l'objet ostream à l'intérieur de wrapper et renvoie l'objet enveloppé. Donc l'opérateur < < < suivant est appelé sur l'objet wrapper, pas sur l'ostream &, et la classe wrapper sait comment imprimer la valeur.

#include <iostream> 
using namespace std; 
class ostream_enum_wrapper_human 
{ 
    public: 
    ostream& out; 
    ostream_enum_wrapper_human(std::ostream& _out) : out(_out){} 

}; 

class ostream_enum_wrapper_int 
{ 
    public: 
    std::ostream& out; 
    ostream_enum_wrapper_int(std::ostream& _out) : out(_out){} 
}; 


enum T{zero,one,two}; 

struct human_readable{} HumanReadable; 
ostream_enum_wrapper_human operator << (ostream& out, human_readable){ 
    return ostream_enum_wrapper_human(out); 
} 

struct print_int{} PrintInt; 
ostream_enum_wrapper_int operator << (ostream& out, print_int){ 
    return ostream_enum_wrapper_int(out); 
} 


ostream& operator << (ostream_enum_wrapper_human out, T t) 
{ 
    switch(t) { 
     case zero: out.out << "zero"; break; 
     case one: out.out << "one"; break; 
     case two: out.out << "two"; break; 
    } 

    return out.out; 
} 

ostream& operator << (ostream_enum_wrapper_int out, T t) 
{ 
    return out.out << static_cast<int>(t); 
} 

int main() 
{ 
    cout << HumanReadable << zero << PrintInt << zero << HumanReadable << two; 
} 

prints zero0two

0

Bien sûr pourquoi pas? Vous devez créer une classe dérivée ostream qui implémente l'écriture dans la base de données, à peu près la même chose que ofstream écrit dans un fichier. Le diable est dans les détails.

2

Vous pouvez tirer parti de la surcharge du premier argument.

//For human-readable output 
std::ostream& operator<< (std::ostream& os, my_enum e); 

//For database; note the absence VVV of & sign here 
std::ostream& operator<< (databasefmt fmt, my_enum e) 
{ 
    std::ostream& os = fmt.stream; 
    // Write data to os 
    // ... 
    return os; 
} 

struct databasefmt{ 
    std::ostream& stream; 
    databasefmt(std::ostream & s) : stream(s) {}; 
}; 

ensuite écrire modificateur de flux qui convertit le flux d'emballage databasefmt classe, de sorte que la sortie à côté de ce flux modifié serait sortie de la base de données pour vous ENUM. Le code d'impression ressemblerait à ceci:

output_stream << "DATA: "<< database_format << my_enum::Value << "END OF DATA" ; 
// Type: std::ostream | databasefmt |   std::ostream   | 

et l'emballage comme celui-ci:

//Variable is needed to avoid confusing parentheses in output operators  
struct databasefmt_converter_t {} database_format; 
// we can't return reference, so we just return fairly small instance of wrapper 
databasefmt operator<< (std::ostream& os, databasefmt_converter_t const&) 
{ return databasefmt(os); } 
+0

Comment 'database_format' serait implémenté? – dalle

+1

Vous renvoyez une référence à une variable locale dans l'opérateur << (std :: ostream & os, __databasefmt_converter &). – dalle

+1

@dalle: Ajout d'un exemple. En passant, "stream modificateurs" une technique commune et a plusieurs implémentations possibles, certains d'entre eux diffèrent de mon exemple. –

0

Le meilleur moyen est d'utiliser std :: :: ios_base xalloc puis std :: ios_base :: iword :

int getxalloc() 
{ 
    static const int ix = std::ios_base::xalloc(); 
    return ix; 
} 

enum my_enum 
{ 
    zero, 
    one, 
    two, 
}; 

std::ostream& operator<<(std::ostream& os, my_enum e) 
{ 
    switch (os.iword(getxalloc()) 
    { 
    default: 
    case 0: 
     os << (int)e; 
     break; 
    case 1: 
     switch (e) 
     { 
     case zero: 
     os << "zero"; 
     break; 
     case one: 
     os << "one"; 
     break; 
     case two: 
     os << "two"; 
     break; 
     default: 
     os << "unknown"; 
     break; 
     } 
     break; 
    } 

    return os; 
} 

int main() 
{ 
    my_enum e = one; 
    std::cout.iword(getxalloc()) = 0; 
    std::cout << e << "\n"; // will output "1" 
    std::cout.iword(getxalloc()) = 1; 
    std::cout << e << "\n"; // will output "one" 
} 

Après cela, vous pouvez ajouter un peu de fantaisie manipulateur de votre propre, au lieu d'utiliser std :: ios_base :: iword directement. Comme ceci:

inline std::ios_base& format_my_enum_as_int(std::ios_base& ib) 
{ 
    ib.iword(getxalloc()) = 0; 
    return ib; 
} 

inline std::ios_base& format_my_enum_as_string(std::ios_base& ib) 
{ 
    ib.iword(getxalloc()) = 1; 
    return ib; 
} 

int main() 
{ 
    my_enum e = one; 
    std::cout << format_my_enum_as_int << e << "\n"; // will output "1" 
    std::cout << format_my_enum_as_string << e << "\n"; // will output "one" 
} 
0

Cette solution est loin d'être parfait; mais il n'y a pas vraiment de gentil à votre problème. Comme vous pouvez le voir, je mets les opérateurs de flux dans les espaces de noms. Par conséquent, je dois inclure l'espace de noms dans le nom actuel. Ceci est simplement fait avec une simple déclaration using.

using namespace xml; 

L'astuce consiste à mettre la déclaration using dans la plus petite portée possible.

Questions connexes