Protokoll: Pakete mit automatischer Serialisierung
-
Sone schrieb:
Arrays funktionieren immer noch nicht...
Dafür gibt es wahrscheinlich auch keine allgemeingültige Lösung. Ursprünglich hatte ich das [1] angefügt, am den Decay zu vermeiden, dann ist mir aufgefallen, dass das ja am falschen Ende angehängt würde. Probleme mit UDTs sehe ich nicht, sofern diese nicht inplace-definiert werden sollen. fun_arg funktioniert nicht mit abstrakten Klassen, aber die können bei dieser Anwendung sowieso nicht auftreten.
-
Kellerautomat schrieb:
Erklaer mal lieber, wie das ganze ueberhaupt funktioniert.
Das ist doch total einfach! Was gibt es da zu erklären?
Was soll's:
Das Grundprinzip hinter diese Variante ist die, dass man innerhalb der Paketklasse für jeden Member eine anonyme union mit zwei Membern definiert:
union { int i; // Der eigentliche, durch das Makro vorgegebene Member. fun_arg< void(int i) > _1; // Der zweite Member, dessen Namen 'wir' wissen };
Da beide Typen exakt gleich sind, können wir problemlos auf _1 oder i zugreifen. Das funktioniert für alle Typen, auch non-PODs, usw.
Das geniale hier ist zudem, dass wir den Namen mit schreiben können, da in der Parameterliste eines Funktionstyp Namen zugelassen sind. Der Nachteil ist, dass Arrays nicht erlaubt sind (siehe auch das gerade hinzugefügtestatic_assert
).Die dump-Funktion nutzt nun _1, _2, und so weiter, während du einfach entweder die von dir festgelegten Identifier nimmst, oder auch _x.
Das kann sogar soweit getrieben werden, dass du sowas schreiben kannst:
DEFINE_PACKET( Foo, TwoWayTag, 0x20, ( int x, std::string s, double d ) ) ( std::ostream& os ) { os << x << ' ' << s.size() << ' ' << s << ' ' << d; }
Und jetzt sag mir, das ist nicht wunderschön.
-
Probleme mit UDTs sehe ich nicht, sofern diese nicht inplace-definiert werden sollen
Dann guck mal, was ich in meinen Destruktor schreiben musste. (UDTs gehen nicht ohne weiteres)
Und die anderen speziellen Memberfunktionen funktionieren auch nicht ohne weiteres; siehe Standard:§9.5/3 schrieb:
[ Example: Consider the following union:
union U { int i; float f; std::string s; };
Since std::string (21.3) declares non-trivial versions of all of the special member functions, U will have an implicitly deleted default constructor, copy/move constructor, copy/move assignment operator, and destructor. To use U, some or all of these member functions must be user-provided.—end example ]
-
Sone schrieb:
(UDTs gehen nicht ohne weiteres)
Das hatte ich überlesen. UDT is ja auch ein bisschen unpräzise.
-
Ich sehe nicht, wie
static_assert( not std::is_array< GET_NTH_TYPE(number, declarations) >::value, "Array type not supported!" );
jemals erfüllt sein könnte.
Sofern für ein array ein typedef existiert und verwendet wird, kann man das Ganze zum funktionieren bringen:
typedef int foo[42]; // als Makroargument: foo x; // ==> using type1 = fun_arg<void(foo x)>; union dummy { foo x, _0; }; // wenn std::is_same<type1, std::decay<decltype(dummy::_0)>::type>::value // so enthält die Deklaration von x keine weiteren Deklaratoren und decltype(dummy::_0) ist der gesuchte Typ // andernfalls verwenden wir type1 // können aber nicht zwischen // int x[42] und int* x unterscheiden
sofern man ein bisschen unportabel wird, könnte man noch Arrays zulassen, deren Größe nicht mit der Größe eines Zeigers übereinstimmt, dann ist die gesuchte Dimension sizeof(dummy) / sizeof(dummy::_0)
statt
DEFINE_PACKET( Foo, TwoWayTag, 0x20, ( int x, std::string s[42], double d ) )
schreibt man dann eben
template <typename T> using simple_typeid = T; DEFINE_PACKET( Foo, TwoWayTag, 0x20, ( int x, simple_typeid<std::string[42]> s, double d ) )
wobei das nicht mehr ganz so schön ist.
-
Ich sehe nicht, wie [...] jemals erfüllt sein könnte.
Ich schon. In dem der entsprechende Typ kein Array ist.
Schon wieder irgend etwas überlesen?
UDT is ja auch ein bisschen unpräzise.
Was soll ich schon schreiben, nicht-triviale Klassen? :p
wobei das nicht mehr ganz so schön ist.
Doch, durchaus verkraftbar. Eine simple Lösung. Leider natürlich nicht so perfekt wie die ideale, aber anwendbar und relativ kurz.
-
Sone schrieb:
Ich sehe nicht, wie [...] jemals erfüllt sein könnte.
Ich schon. In dem der entsprechende Typ kein Array ist.
Schon wieder irgend etwas überlesen?
umgekhhrt nat.:
not std::is_array< GET_NTH_TYPE(number, declarations) >::value
kann niemals false sein, fun_arg<...> ist unter keinen Umständen ein Array.
Sone schrieb:
Aber das ist doch auch trivial. Dass man einfach den Array-Typ in einem Wrapper verpackt, der selbst natürlich kein Array-Typ mehr ist. Dann testet man einfach nur noch irgendwo intern, ob
fun_arg<...>
eine Spezialisierung von diesem Wrapper-Template ist, und nimmt dann entsprechend das Argument des Templates als Typ. Und dann kommt man noch drauf, dass es eine alias-Deklaration sein muss, weil sonst der Typ des ersten Union-Members der Typ des Wrappers und nicht des gewrappten Typs ist. Und dann kommt man drauf, dass man dann auch nicht mehr testen kann oder braucht.???
-
kann niemals false sein, fun_arg<...> ist unter keinen Umständen ein Array
Arghh, verdammt! Ich übersehe immer solche Kleinigkeiten... ja, das ist natürlich eine sinnfreie Abfrage. Dann wird der User wohl oder übel sorgfältig die Dokumentation lesen müssen.
Mich wurmt es immer noch, dass man den Typ nicht so leicht bekommen kann... das muss doch einfacher gehen...!
???
Ach, natürlich, das muss alias-Template heißen....
Damit wollte ich nur darlegen, dass der Schreiber dieses Makros selbst nichts machen muss, da der User da von selbst drauf kommt, wenn er sich das Prinzip ansieht. Zugegeben ein wenig kontext-frei... daher raus editiert...
-
Wusste gar nicht, dass man Makro-Parameter einfach leer lassen kann. Gibts dazu nicht BOOST_PP_EMPTY?
Ausserdem hat C++ meines Wissens nach keine anonymen Unions.Anonsten finde ich hustbaers Ansatz immer noch schoener, sorry
-
Kellerautomat schrieb:
Wusste gar nicht, dass man Makro-Parameter einfach leer lassen kann. Gibts dazu nicht BOOST_PP_EMPTY?
Nein, kann man lehr lassen.
BOOST_PP_EMPTY
ist eine Makro-Funktion, die zu nichts evaluiert, die nutzt man also dort wo man den Namen einer Makro-Funktion uebergeben will.Ausserdem hat C++ meines Wissens nach keine anonymen Unions.
Jetzt weisst du es besser. Siehe auch Standard 9.5.5.
Anonsten finde ich hustbaers Ansatz immer noch schoener, sorry
Meiner ist genauso flexibel. Du musst das Serialisierungs- und Deserialisierungs-Makro genauso definieren... dazu musst du nichts mehrfach einbinden... und es ist kuerzer ein Paket zu definieren... was genau ist bei hustbaer schoener? AFAICS nichts.
-
Du Frage muss lauten: Was ist haesslicher? Schoen sind beide nicht.
-
knivil schrieb:
Du Frage muss lauten: Was ist haesslicher?
Es ist voellig egal, was man fragt. Schoenheit ist relativ, genau wie Haesslichkeit.
(Sprich: Wenn A hässlicher ist als B, ist B schöner als A, und vice versa)Und ja, sie sind beide nicht schoen, da hast du Recht.
-
Kann ich mit deinem Ansatz beliebigen weiteren Code pro Paket erzeugen, ohne die Paket-Klasse oder das Makro zu veraendern? Ich denke nicht.
hustbaers ist nonintrusiv, das finde ich besser. Und den Mehraufwand in der Definition koennte man durch ein zusammenfassendes Makro auch noch beseitigen.
-
Kellerautomat schrieb:
Kann ich mit deinem Ansatz beliebigen weiteren Code pro Paket erzeugen, ohne die Paket-Klasse oder das Makro zu veraendern? Ich denke nicht.
hustbaers ist nonintrusiv, das finde ich besser. Und den Mehraufwand in der Definition koennte man durch ein zusammenfassendes Makro auch noch beseitigen.
Das. Dokumentieren muss man sowieso. Ich war nur daran interessiert, herauszubekommen, ob man die ursprüngliche Syntax überhaupt umsetzen kann.