2010-05-03 15 views
16

C++ consideri una struttura semplice:valori di stampa di tutti i campi di una struttura

struct abc 
{ 
    int a; 
    char b; 
} 

ho avuto qualche valore in una variabile definita come la sua struttura, e ora voglio stampare il seguito.

*a = [some value] 
b = [some character]* 

Qual è il modo migliore per raggiungere questo obiettivo per una struttura arbitraria senza dover scrivere una discarica ... (...) funzione per ogni della struttura che incontro?

+1

Ebbene, dopo aver scritto questa domanda, ho casualmente fatto google e trovato sotto discussione http://stackoverflow.com/questions/1878285/iterate-over-struct-easily-display-struct-fields-and-values-in-a-richedit-box Penso che risponda a tutti i miei dubbi. Grazie a tutti per la risposta però. – Zhinkaas

risposta

2

Non ce n'è uno, non in C++. Dura fortuna

+0

Ci sono vari modi per avere questo: metaprogrammazione del modello, analisi o generazione di classi con uno strumento esterno. Non dimenticare che molte cose sono possibili con i computer, anche se forse non facilmente o nel modo in cui hai pensato che dovrebbe essere. –

2

I compilatori C++ non producono metadati. Quindi non c'è modo di fare una cosa del genere.

+0

I compilatori C++ non producono metadati, ma i metadati a cui siamo interessati sono disponibili in fase di compilazione che richiede la metaprogrammazione del modello :) –

0

Se si utilizza C++ in .NET, è possibile utilizzare la roba System.Reflection per esaminare l'interno della struttura. C++ non gestito raramente, se mai, memorizza quel tipo di metadati sugli oggetti, però.

0

Questo non può essere fatto, perché non c'è riflessione in C++. Tuttavia, se non si desidera scrivere da soli il codice boilerplate, è sempre possibile scrivere alcuni strumenti per farlo.

+1

Penso che tu abbia sbagliato l'introspezione per la riflessione. Dall'articolo di wikipedia sull'introspezione: http://en.wikipedia.org/wiki/Type_introspection, puoi vedere un esempio di introspezione in C++ usando 'typeid'. –

+0

Sì, l'ho visto troppo tardi. Ho lasciato la risposta per la parte del boilerplate. – stefaanv

3

Hai bisogno di "riflessione" per fare questo. Reflection non è fornito in modo nativo in C++, o solo per informazioni minime (tipo id/nomi).

Esistono librerie (come CAMP) che implementano le funzioni di riflessione, quindi se VERAMENTE avete bisogno di una riflessione, dovreste usarne una.

+2

Github del campo https://github.com/tegesoft/camp – TankorSmash

22

Sembra che tu abbia già trovato la soluzione, ma mi espanderò un po '.

Quello che stai chiamando si chiama Reflection, ovvero la capacità di un oggetto di descriversi.

La maggior parte delle lingue implementa la riflessione grazie ai metadati, in Python, ad esempio, le funzioni e gli attributi di un oggetto sono memorizzati in un elemento del dizionario.

C++ non ha alcun sistema di riflessione nativo a differenza di C# o Java, che impedisce (ad esempio) questo tipo di stampa/serializzazione o deserializzazione automatica.

Tuttavia, C++ dispone di un supporto per metaprogrammazione molto potente che ci consente (tramite l'uso di modelli) di emulare il riflesso (in fase di compilazione). Di solito questo viene fatto usando Boost.Fusion, questa libreria è pensata per passare dal tempo di compilazione a quello di esecuzione.

Come nell'esempio illustrato nel collegamento, la macro consente di prendere uno standard struct e di fornire l'interfaccia necessaria per essere considerata Fusion.Sequence.

Un altro esempio potrebbe essere quello di utilizzare Fusion.Vector o Fusion.Map per memorizzare gli attributi della classe e poi esporre questa sequenza per metodi automatici di stampa/di serializzazione/deserializzazione.

Tuttavia, esiste un limite a questo sistema: la metaprogrammazione non si adatta bene alla programmazione OO.

struct Base { char a; };   // Adapt 
struct Derived: Base { char b; }; // Adapt 

void print(Base const& b) { boost::fusion::for_each<Base>(b, Print()); } 

sarà stampare solo il membro del Base (qui a).Quando si utilizza il polimorfismo, è necessario utilizzare metodi virtual in un punto o un altro :)

+0

Mi piace la soluzione fusion.adapt.struct. [Chiesto in particolare su come scendere nei campi struct annidati e ha funzionato tutto] (http://stackoverflow.com/a/12102144/362754). – minghua

0

Questo può essere fatto utilizzando la Visitor disegno del modello:

struct MyStruct; // Forward declaration 

struct Writer 
{ 
    virtual void operator(MyStruct& m) = 0; 
}; 

struct MyStruct 
{ 
    void write(Writer& w) 
    { 
     // Invoke the writer's method for this class. 
     w(*this); 
    } 
    int a; 
    double b; 
}; 

struct File_Writer 
{ 
    File_Writer(ofstream& output) 
    : m_output(output) 
    { ; } 
    void operator(MyStruct& ms) 
    { 
     output << ms.a << endl; 
     output << ms.b << endl; 
    } 
    ofstream& m_output; 
}; 

struct Display_Writer 
{ 
    void operator(MyStruct& ms) 
    { 
     cout << " a: " << ms.a << endl; 
     cout << " b: " << ms.b << endl; 
    } 
}; 

int main(void) 
{ 
    MyStruct ms; 
    ms.a = 5; 
    ms.b = 4.2; 

    // Write to the display, without changing methods in MyStruct 
    Display_Writer dw; 
    ms.write(dw); 

    // Write to a file without changing methods in MyStruct 
    ofstream my_file("me.txt"); 
    File_Writer fw(my_file); 
    ms.write(fw); // Notice that only the writer object changed. 

    return 0; 
} 
+0

Visitatore vuol dire che devi scrivere tu stesso il codice boilerplate, che l'OP desidera specificamente NON fare. –

Problemi correlati