2010-12-29 9 views

Antwort

3

Ich habe gerade nachgeschaut, was ein X-Macro sein soll und ich denke, ich habe etwas getan, was du verlangst.

Ich wollte einfach und schnell Serialisierung für eine Reihe von ziemlich ähnlichen Klassen unterstützen. Das Problem, das ich hatte, war, dass ich einige Laufzeitinformationen (ein int) in einen Kompilierzeittyp (eine Klasse) umwandeln musste, um meine Serialisierung durchführen zu können. Ich hätte einige Case-Statements schreiben können, um das zu tun, aber das würde bedeuten, dass ich jedes Mal mehrere Funktionen aktualisieren müsste, wenn ich eine Klasse hinzufügen wollte.

, um dieses Problem, ich definierten ersten a sequence von tuples die Abbildung enthält:

#define WIN_MESSAGE_TYPE_SEQ \ 
    ((EM_REPLACESEL, em_replacesel))((WM_CHAR, wm_char)) //... 

Die Großbuchstaben Namen sind definiert, die einen int und die Kleinnamen sind Klassen halten, die ich irgendwo anders definiert.

Ich kann dann diese Sequenz in Verbindung mit einigen der Boost preprocessors verwenden, um alle Arten von Code für mich zu generieren. Zum Beispiel kann ich dies nur tun, um eine Vorwärts-Deklaration der Klassen zu erhalten:

#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \ 
    class BOOST_PP_TUPLE_ELEM(2,1,_elem_); 

BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ) 

#undef WIN_MESSAGE_TYPE_BUILD_MACRO 

die Laufzeit zu tun, um Zeitzuordnung zu kompilieren, erzeuge ich eine Reihe von Fall Aussagen wie folgt aus:

#define WIN_MESSAGE_TYPE_BUILD_MACRO(r, _data_, _elem_) \ 
    case BOOST_PP_TUPLE_ELEM(2,0,_elem_): return win_message_serializer<BOOST_PP_TUPLE_ELEM(2,1,_elem_)>::serialize(msg, o_arch); 

template <typename Archive> 
void serialize_win_message (p_win_message_base msg, Archive& o_arch) { 
    message_type_t message_type = msg->type(); 

    switch (message_type) { 

    // This will generate a series of case statement for each message type that will invoke 
    // the serializer for the correct types. 
    BOOST_PP_SEQ_FOR_EACH(WIN_MESSAGE_TYPE_BUILD_MACRO, BOOST_PP_NIL, WIN_MESSAGE_TYPE_SEQ) 

    default: //... 
    }; 
} 

#undef WIN_MESSAGE_TYPE_BUILD_MACRO 

Der ganze Code beinhaltet ein bisschen mehr als das, aber das sollte Ihnen noch eine Idee geben, wie man Code mit den Boost Preprozessoren erzeugt. In meinem Beispiel kann ich die Serialisierungsunterstützung für eine Klasse schnell und einfach hinzufügen, indem ich einfach meine Sequenz aktualisiere.

Beachten Sie, dass die Verwendung des Boost-Präprozessors keinen sehr lesbaren Code erzeugt, daher versuche ich, das Makro für jedes Makro so einfach wie möglich zu halten. Auch wäre ich nicht überrascht, wenn jemand irgendwo eine elegantere Lösung für dieses Problem hätte. Dies ist genau das, was ich mir für ein persönliches Projekt ausgedacht habe, wo mir die zusätzliche Komplexität nichts ausmacht.