2 Template Funktionen zusammenfassen?
-
Ich habe 2 Konvertierungsfunktionen: "Struct --> String" und "String --> Struct":
Beispiel für die generelle Struktur:
struct STestStruct { int TestInt; }; #define TO_STRING(Var) ConvertToString(Input.Var, Output); template <class StrCls> void ConvertToString(const STestStruct& Input, StrCls& Output) { TO_STRING(TestInt) } #define FROM_STRING(Var) ConvertFromString(StrValue, Output.Var); template <class StrCls> void ConvertFromString(const StrCls& StrValue, STestStruct& Output) { FROM_STRING(TestInt) }Aktuell taucht demnach jede Membervariable des Structs (hier TestInt) 2 mal im Quellcode auf: 1 mal in ConvertToString, einmal in ConvertFromString.
Gäbe es evtl. eine Möglichkeit, dass man nur 1 Macro verwenden muss? Ich stelle mir so was wie das hier vor:
#define CONVERT(var) \ if (bToString) \ ConvertToString(Struct.Var, Output); \ else \ ConvertFromString(StrValue, Output.Var); template <class StrCls, class StructCls, class OutputCls, bool bToString> void GenericStructConversion(const StrCls& StrValue, const StructCls& Struct, OutputCls& Output) { CONVERT(TestInt) } template <class StrCls> void ConvertToString(const STestStruct& Input, StrCls& Output) { GenericStructConversion<StrCls, STestStruct, StrCls, true>(Output, Input, Output); } template <class StrCls> void ConvertFromString(const StrCls& StrValue, STestStruct& Output) { GenericStructConversion<StrCls, STestStruct, STestStruct, false>(StrValue, Output, Output); }Das funktioniert leider nicht, weil der Compiler verständlicherweiße "Output.TestInt" nicht finden kann, falls GenericStructConversion() von ConvertToString() aufgerufen wird (weil Output dann ein string ist...).
Bei solch einer Struktur würde aber eben ein Makro in GenericStructConversion() reichen, anstatt jeweils eines in ConvertToString() und ConvertFromString().
Geht das?

EDIT: Da fällt mir noch eine Frage ein (hat mit der obigen nichts zu tun). Kann man eine Templatefunktion "partiell", hier z.B. bezüglich bToString spezialisieren?
template <class StrCls, class StructCls, class OutputCls> void GenericStructConversion<true>(const StrCls& StrValue, const StructCls& Struct, OutputCls& Output) { }
-
Was frickelst du überhaupt mit Makros rum? Da kannst du doch Funktionsüberladung nehmen...
Andere Frage: Welchen Vorteil hat
GenericStructConversion<..., true>(...); GenericStructConversion<..., false>(...);gegenüber
ConvertToString(...); ConvertToStruct(...);Und nein, Funktionstemplates kann man im aktuellen C++-Standard nicht partiell spezialisieren, wohl aber überladen, und damit kommt man schon recht weit.
-
Nun ja, ich habe halt mehrere ConvertToString und ConvertFromString Überladungen/Spezialisierungen (z.B. Support für std::vector, etc.).
Jetzt habe ich Hilfsfunktionen geschrieben, so dass man auf einfache Weise Unterstützung von eigenen Structs/Klassen durch Überladung von ConvertToString/ConvertFromString hinzufügen kann. Die Funktionen werden von einer Ini-Datei Bibliothek aufgerufen.
Nach dem Makro-#define steht auch nicht viel Code, meist nur 1 Funktionsaufruf. Durch das Makro muss man aber die Variable nicht zweimal angeben (es wird der Name der Variablen und halt die Variable selbst benötigt).
Aufjedenfall sind die Makros in dem Fall völlig irrelevant... (Warum hab ich die eigtl. gepostet?
)Es geht darum, dass ich in diesem Fall (eigene Structs) den Konvertierungscode von ConvertToString() und ConvertFromString() in eine einzige Funktion packen möchte.
-
EDIT: Da fällt mir noch eine Frage ein (hat mit der obigen nichts zu tun). Kann man eine Templatefunktion "partiell", hier z.B. bezüglich bToString spezialisieren?
Nein. Bei Template Funktionen gilt: Ganz oder gar nicht spezialisieren.
Es geht darum, dass ich in diesem Fall (eigene Structs) den Konvertierungscode von ConvertToString() und ConvertFromString() in eine einzige Funktion packen möchte.
Suchst du so etwas:
void Convert (STestStruct& val_1, StrCls& val_2, bool ToString ) {//... }?
-
Mh, so ähnlich. Das Probleme an dem Entwurf sind (bei meinem aktuellen Design):
- Ich must "const" wegcasten (in ConvertFromString z.B. ist StrValue konstant)
- Es löst nicht das eigtl. Problem, wie ich es in Post 1 beschrieben habe (den Compilerfehler)
Ich habs jetzt mit einem zusätzlichen Parameter hingekriegt, und zwar grundsätzlich so:
template <class StrCls> void GenericStructConversion(EConversionDirection Dir, const StrCls* InputStrValue, const STestStruct* InputStruct, StrCls* OutputStr, STestStruct* OutputStruct) { using namespace Conversion; if (Dir == CD_TO_STRING) StructVariableToString(_T("TestInt"), InputStruct->TestInt, *InputStruct, *OutputStr); else ExtractAndConvertStructValue(*InputStrValue, _T("TestInt"), *OutputStruct, OutputStruct->TestInt); } template <class StrCls> void ConvertToString(const STestStruct& Input, StrCls& Output) { GenericStructConversion<StrCls, STestStruct>(CD_TO_STRING, NULL, &Input, &Output, NULL); } template <class StrCls> void ConvertFromString(const StrCls& StrValue, STestStruct& Output) { GenericStructConversion<StrCls, STestStruct>(CD_FROM_STRING, &StrValue, NULL, NULL, &Output); }Es ist zwar nicht besonders schön, aber ich glaube dass ich es besser nicht ohne größere allgemeine Änderungen hinbekomme...
Danke für die Antworten

-
Ich halte das Funktionstemplate
GenericStructConversion()nach wie vor für sehr fragwürdig.Gugi schrieb:
Es geht darum, dass ich in diesem Fall (eigene Structs) den Konvertierungscode von ConvertToString() und ConvertFromString() in eine einzige Funktion packen möchte.
-> Du willst generisch bleiben.
-> Dein krampfhafter Versuch, nur eine Funktion zu verwenden, endet in nicht benutzen Dummy-Parametern und einer If-Abfrage, was die Funktion tun soll.
-> Was bringt dir das? Das ist alles andere als generisch, geschweige denn schön.Sag doch einfach, wieso du meinst, 2 Funktionen wären ungeeignet.
-
Ne, generisch soll die Funktion, die beides macht, nicht sein. Der Name ist einfach wohl schlecht gewählt^^
Also, es ist natürlich kein Problem sowohl ConvertFromString() als auch ConvertToString() zu überladen, und bei weitem nicht ungeeignet.
Das sieht aktuell so aus (hinter jedem Makro steckt kaum mehr als ein Funktionsaufruf):// ConvertFromString CFS_BEGIN_STRING_TO_STRUCT_CONVERSION(STestStruct) CFS_READ_VAR_FULL(_T("MyTestInt"), Output.TestInt); CFS_READ_VAR_WITH_SAME_NAME(TestBool); CFS_READ_VAR_WITH_SAME_NAME(TestWStr); CFS_READ_VAR(_T("JustANestedStruct"), NestedStruct); CFS_READ_VAR_WITH_SAME_NAME(TestIntVector); CFS_READ_VAR_WITH_SAME_NAME(TestNest2Deque); CFS_END_STRING_TO_STRUCT_CONVERSION() // ConvertToString CTS_BEGIN_STRUCT_TO_STRING_CONVERSION(STestStruct) CTS_WRITE_VAR_FULL(_T("MyTestInt"), Input.TestInt); CTS_WRITE_VAR(_T("JustANestedStruct"), NestedStruct); CTS_WRITE_VAR_WITH_SAME_NAME(TestBool); CTS_WRITE_VAR_WITH_SAME_NAME(TestWStr); CTS_WRITE_VAR_WITH_SAME_NAME(TestIntVector); CTS_WRITE_VAR_WITH_SAME_NAME(TestNest2Deque); CTS_END_STRUCT_TO_STRING_CONVERSION()Wie man sieht, muss man 2 mal z.B. TestIntVector angeben, und man braucht überhaupt 2 "Makro-Blöcke", obwohl eigtl. beide mehr oder weniger gleich aussehen.
Für denn Fall, dass keine Besonderheiten gebraucht werden, fände ich besser, wenn man nur 1 Block benötigt. Und da muss ich dann halt beide Funktionen zu einer zusammenfassen. Das ermöglicht dann, dass nur 1 anstatt 2 solcher Blöcke schreiben muss.Wenn man es getrennt macht, dann würde ich halt bei einem neuen Struct erst 1 Block schreiben, dann kopieren und einfach die Makros austauschen.
Und wenn es eine Möglichkeit gibt, beides zusammenzufassen, warum nicht? Wenn man eine Variable zu dem Struct hinzufügt, muss man dann nur noch zusätzlich 1 Zeile Code anstatt 2 hinzufügen, und die Gefahr, dass man eine Zeile vergisst, gibt es auch nicht.Wenn man durch die Makros hindurchsieht, mag dass zwar äußert unschön sein, aber anders wird es nachträglich wohl nicht gehen (ich müsste dann das ganze Konvertierungssystem umschreiben...).
-
Gugi schrieb:
(hinter jedem Makro steckt kaum mehr als ein Funktionsaufruf):
Dann lass die Makros doch weg und bleib bei Funktionen. Alles was du bisher in Makros gemacht hast kannst du auch mit normalen Funktionen machen. Makros sind einfach sch***, und es gibt nur wenige Ausnahmen, wo man sie nicht drumrum kommt - das ist hier aber nicht der Fall.
-
Vorweg: Sry für den vielen Code und die Definition von STestStruct sieht so aus (für SNestedStruct sind ebenfalls Convert Überladungen nötig):
struct STestStruct { int TestInt; std::wstring TestWStr; bool TestBool; SNestedStruct NestedStruct; std::vector<int> TestIntVector; std::deque<SNest2> TestNest2Deque; };Wenn ich die Lib benutzte, ziehe ich persönlich so was:
CTS_BEGIN_STRUCT_TO_STRING_CONVERSION(STestStruct) CTS_VAR_TO_STRING_WSN(TestInt); CTS_VAR_TO_STRING_WSN(TestBool); CTS_VAR_TO_STRING_WSN(TestWStr); CTS_VAR_TO_STRING_WSN(NestedStruct); CTS_VAR_TO_STRING(_T("CustomNameIntVect", TestIntVector); CTS_VAR_TO_STRING_WSN(TestNest2Deque); CTS_END_STRUCT_TO_STRING_CONVERSION()diesem hier:
template <class StrCls> void ConvertToString(const STestStruct& Input, StrCls& Output) { using namespace Conversion; Output = ConvertFromString<std::string, StrCls>("("); // Gut, kann man noch in eine eigene Funktion packen... StructVariableToString(_T("TestInt"), Input.TestInt, Input, Output); StructVariableToString(_T("TestBool"), Input.TestBool, Input, Output); StructVariableToString(_T("TestWStr"), Input.TestWStr, Input, Output); StructVariableToString(_T("NestedStruct"), Input.NestedStruct, Input, Output); StructVariableToString(_T("CustomNameIntVect"), Input.TestIntVector, Input, Output); StructVariableToString(_T("TestNest2Deque"), Input.TestNest2Deque, Input, Output); EndStructToStrConversion(Output); }vor.
----------
Falls ich noch ConvertFromString() überladen möchte, muss ich noch das:
CFS_BEGIN_STRING_TO_STRUCT_CONVERSION(STestStruct) CFS_VAR_FROM_STRING_WSN(TestInt); CFS_VAR_FROM_STRING_WSN(TestBool); CFS_VAR_FROM_STRING_WSN(TestWStr); CFS_VAR_FROM_STRING_WSN(NestedStruct); CFS_VAR_FROM_STRING(_T("CustomNameIntVect", TestIntVector); CFS_VAR_FROM_STRING_WSN(TestNest2Deque); CFS_END_STRING_TO_STRUCT_CONVERSION()oder eben so was:
template <class StrCls> void ConvertFromString(const StrCls& StrValue, STestStruct& Output) { using namespace Conversion; CheckStructLikeStringForErrors(StrValue, Output); StructVariableFromString(StrValue, _T("TestInt"), Output, Output.TestInt); StructVariableFromString(StrValue, _T("TestBool"), Output, Output.TestBool); StructVariableFromString(StrValue, _T("TestWStr"), Output, Output.TestWStr); StructVariableFromString(StrValue, _T("NestedStruct"), Output, Output.NestedStruct); StructVariableFromString(StrValue, _T("CustomNameIntVect"), Output, Output.TestIntVector); StructVariableFromString(StrValue, _T("TestNest2Deque"), Output, Output.TestNest2Deque); }schreiben.
----------
Falls die Variablennamen die gleichen sind, würde ich es vorziehen, wenn ich nur 1 mal so nen "Block" schreiben müsste, anstatt 2. Mir wäre da ebenfalls so was:
BDC_BEGIN_BIDIR_STRUCT_STRING_CONVERSION(STestStruct) BFC_VAR_CONVERSION_WSN(TestInt); BFC_VAR_CONVERSION_WSN(TestWStr); BFC_VAR_CONVERSION_WSN(TestBool); BFC_VAR_CONVERSION_WSN(NestedStruct); BFC_VAR_CONVERSION(_T("CustomNameIntVect"), TestIntVector); BFC_VAR_CONVERSION_WSN(TestNest2Deque); BDC_END_BIDIR_STRUCT_STRING_CONVERSION()also so was:
template <class StrCls> inline void ConvertToString(const STestStruct& Input, StrCls& Output) { BidirectionalStructConversion(Conversion::CD_TO_STRING, static_cast<const StrCls*>(NULL), &Input, &Output, static_cast<STestStruct*>(NULL)); } template <class StrCls> inline void ConvertFromString(const StrCls& StrValue, STestStruct& Output) { BidirectionalStructConversion(Conversion::CD_FROM_STRING, &StrValue, static_cast<const STestStruct*>(NULL), static_cast<StrCls*>(NULL), &Output); } template <class StrCls> void BidirectionalStructConversion(Conversion::EConversionDirection Dir, const StrCls* InputStrValue, const STestStruct* InputStruct, StrCls* OutputStr, STestStruct* OutputStruct) { using namespace Conversion; if (Dir == CD_TO_STRING) { assert(OutputStr != NULL && InputStruct != NULL); (*OutputStr) = MB_TO_STRCLS("("); } else { assert(OutputStruct != NULL && InputStrValue != NULL); CheckStructLikeStringForErrors(*InputStrValue, *OutputStruct); } if (Dir == CD_TO_STRING) StructVariableToString(_T("TestInt"), InputStruct->TestInt, *InputStruct, *OutputStr); else StructVariableFromString(*InputStrValue, _T("TestInt"), *OutputStruct, OutputStruct->TestInt); if (Dir == CD_TO_STRING) StructVariableToString(_T("TestWStr"), InputStruct->TestWStr, *InputStruct, *OutputStr); else StructVariableFromString(*InputStrValue, _T("TestWStr"), *OutputStruct, OutputStruct->TestWStr); if (Dir == CD_TO_STRING) StructVariableToString(_T("TestBool"), InputStruct->TestBool, *InputStruct, *OutputStr); else StructVariableFromString(*InputStrValue, _T("TestBool"), *OutputStruct, OutputStruct->TestBool); if (Dir == CD_TO_STRING) StructVariableToString(_T("NestedStruct"), InputStruct->NestedStruct, *InputStruct, *OutputStr); else StructVariableFromString(*InputStrValue, _T("NestedStruct"), *OutputStruct, OutputStruct->NestedStruct); if (Dir == CD_TO_STRING) StructVariableToString(_T("CustomNameIntVect"), InputStruct->TestIntVector, *InputStruct, *OutputStr); else StructVariableFromString(*InputStrValue, _T("CustomNameIntVect"), *OutputStruct, OutputStruct->TestIntVector); if (Dir == CD_TO_STRING) StructVariableToString(_T("TestNest2Deque"), InputStruct->TestNest2Deque, *InputStruct, *OutputStr); else StructVariableFromString(*InputStrValue, _T("TestNest2Deque"), *OutputStruct, OutputStruct->TestNest2Deque); if (Dir == CD_TO_STRING) EndStructToStrConversion(*OutputStr); }lieber. Allerdings macht die BidirectionalStructConversion() Funktion überhaupt keinen Sinn, wenn man nicht die Makros verwendet, weil es einfacher (und sicherer) ist, die beiden Convert Funktionen zu schreiben. Sie ist auch nur eine im Nachhinein aufgesetzte Behelfsfunktion, damit man mit einem Makro-Block beide Konvertierungen implementieren kann.
Die Vorteile an den Makro Versionen sind in meinen Augen:
- Für den normalen Fall, dass, falls man den gleichen VariablenName im string wie auch im eigtl. Code wünscht, nur 1 mal eben diesen Name schreiben muss.
- Weiterhin sieht man direkt, welche Variablen mit anderem Namen geschrieben werden.
- Man muss nicht immer Input und Output schreiben.
- Man kann keinen Fehler bei dem Funktionsheader machen (falscher Name, falsche Argumente, etc.)
- Man vergisst nicht, EndStructToStrConversion() und eben die anderen Funktionen aufzurufen.
- Man kann dann eben beide Convert Funktionen mit nur 1 solchen Block implementieren. Und meist sind beide Richtungen gewünscht.Nachteile:
- Es sind eben Makros, mit all ihren Problemen (nicht Typsicher, Compilermeldungen werden rätselhafter,...)
- Die Blöcke sehen nicht wie Funktionen aus, was bei der Fehlersuche sich als ein Stolperstein ergeben könnte.
--> Es ist eben sofort klar, was hier geschieht, weil die Makros es nicht überdecken
-
Hmm, mir ist das irgendwie zuviel Code. Du moechtest also Objekte serialisieren? Wenn das so ist, dann gibt es elegantere Methoden in C++. Zumal ich gerade nicht den Sinn hinter dem ganzen sehe, da bei der Nutzung deiner Funktionen dem Anwender keinerlei Arbeit abgenommen wird. Fuer jede Klasse muss trotzdem die Serialisierung haendisch implementiert werden, nur dass jetzt deine tollen Makros benutzt werden. Wo ist der Vorteil gegenueber einem einfachen Ueberladen der Streamoperatoren? Was ist, wenn ich in meinen Klassen Member habe, die nicht von deinen Makros abgedeckt werden?
ich müsste dann das ganze Konvertierungssystem umschreiben
Nennt sich Refactoring und das ist bitter noetig. Vielleicht ist das ein Fall fuer The daily WTF
-
knivil schrieb:
ich müsste dann das ganze Konvertierungssystem umschreiben
Nennt sich Refactoring und das ist bitter noetig. Vielleicht ist das ein Fall fuer The daily WTF
unabhängig davon sieht
if (Dir == CD_TO_STRING) StructVariableToString(_T("TestInt"), InputStruct->TestInt, *InputStruct, *OutputStr); else StructVariableFromString(*InputStrValue, _T("TestInt"), *OutputStruct, OutputStruct->TestInt);so aus, als ob hier nen makro oder ne fkt keine schlechte idee wäre...
bb
-
knivil schrieb:
Wo ist der Vorteil gegenueber einem einfachen Ueberladen der Streamoperatoren?
Die ganzen Konvertierungsgeschichten sollen zwar weitestgehend unabhängig sein (für den Fall, dass ich sie später nochmal brauche), aber ich benutzte sie im Moment hauptsächlich für meine Ini library. Dabei brauche ich eben Konvertierungen von und zu strings.
Ich hab zuerst einfach die stream operatoren benutzt. Das Problem fing dann bei strings an: der >> operator liest nur bis zum nächsten Leerzeichen. Weiterhin wollte ich sowohl std::wstring also auch std::string unabhängig von dem benutzten Charset unterstützen. Dann ging es weiter mit char und wchar_t und signed und unsigned char. >> für std::wstring z.B. zu überladen geht nicht, weil die STL bereits einen vorgibt.Das ganze war als eine (nicht Klassen) Templatefunktion implementiert, welche dann von der Ini-Klasse die Schreib/Lese-Funktion aufrief, nach dem die Konvertierung vollzogen wurde.
Da ich es furchtbar fand, immer diese Funktion zu überladen (für wstring, string, etc.) (es stand noch ein bisschen mehr drin), hab ich die Konvertierung ausgelagert: eben in ConvertFromString() und ConvertToString().Weiterhin gibt es immer noch eine Version von ConvertFromString() und ConvertToString(), welche die Stream operatoren aufrufen.
Der Client kann dann also selbst entscheiden, ob er >> bzw. << oder eben die Konvertierungsfunktionen überläd.
Ich hab mir auch gedacht, dass man evtl. nur für die Ini-Lib solch eine Konvertierung möchte, und bei anderen "Sachen" eben eine andere. Wenn diese "anderen" Sachen jetzt den stream operator benutzten, und man diesen für die Ini-Lib überladen hat, geht das nicht mehr.----
knivil schrieb:
Hmm, mir ist das irgendwie zuviel Code.
Meinst du, dass ich zu viel Code gepostet habe? Sorry

knivil schrieb:
Zumal ich gerade nicht den Sinn hinter dem ganzen sehe, da bei der Nutzung deiner Funktionen dem Anwender keinerlei Arbeit abgenommen wird. Fuer jede Klasse muss trotzdem die Serialisierung haendisch implementiert werden, nur dass jetzt deine tollen Makros benutzt werden.
Serialisierungen müssen doch in C++ immer per Hand implementiert werden, weil so was wie Reflection fehlt?
Und ich weiß nicht, aber für mich ist das eine deutige Arbeitserleichterung, wenn ich statttemplate <class StrCls> void ConvertToString(const STestStruct& Input, StrCls& Output) { using namespace Conversion; Output = ConvertFromString<std::string, StrCls>("("); // Gut, kann man noch in eine eigene Funktion packen... StructVariableToString(_T("TestInt"), Input.TestInt, Input, Output); StructVariableToString(_T("TestBool"), Input.TestBool, Input, Output); StructVariableToString(_T("TestWStr"), Input.TestWStr, Input, Output); StructVariableToString(_T("NestedStruct"), Input.NestedStruct, Input, Output); StructVariableToString(_T("CustomNameIntVect"), Input.TestIntVector, Input, Output); StructVariableToString(_T("TestNest2Deque"), Input.TestNest2Deque, Input, Output); EndStructToStrConversion(Output); } template <class StrCls> void ConvertFromString(const StrCls& StrValue, STestStruct& Output) { using namespace Conversion; CheckStructLikeStringForErrors(StrValue, Output); StructVariableFromString(StrValue, _T("TestInt"), Output, Output.TestInt); StructVariableFromString(StrValue, _T("TestBool"), Output, Output.TestBool); StructVariableFromString(StrValue, _T("TestWStr"), Output, Output.TestWStr); StructVariableFromString(StrValue, _T("NestedStruct"), Output, Output.NestedStruct); StructVariableFromString(StrValue, _T("CustomNameIntVect"), Output, Output.TestIntVector); StructVariableFromString(StrValue, _T("TestNest2Deque"), Output, Output.TestNest2Deque); }folgendes schreiben kann:
BDC_BEGIN_BIDIR_STRUCT_STRING_CONVERSION(STestStruct) BFC_VAR_CONVERSION_WSN(TestInt); BFC_VAR_CONVERSION_WSN(TestWStr); BFC_VAR_CONVERSION_WSN(TestBool); BFC_VAR_CONVERSION_WSN(NestedStruct); BFC_VAR_CONVERSION(_T("CustomNameIntVect"), TestIntVector); BFC_VAR_CONVERSION_WSN(TestNest2Deque); BDC_END_BIDIR_STRUCT_STRING_CONVERSION()knivil schrieb:
Was ist, wenn ich in meinen Klassen Member habe, die nicht von deinen Makros abgedeckt werden?
Falls du Set-Funktionen meinst, dann müsste ich entweder noch solch ein Makro hinzufügen, oder die Konvertierungsfunktion muss als friend deklariert werden, oder man darf die Makros einfach nicht verwenden?
Falls du weitere Structs, Klassen, etc. meinst, dann müssen weitere ConvertFromString()/ConvertToString() Versionen erstellt werden, für denn Fall, dass man diese Membervariable mit im String hat.
Ist das falsch?

knivil schrieb:
Nennt sich Refactoring und das ist bitter noetig. Vielleicht ist das ein Fall fuer The daily WTF
Das Problem: Ich hab leider keine Ahnung, was ich jetzt genau wie verbessern könnte. Ich bin kein professioneller Programmierer, und hab bloß ein paar Bücher gelesen, und versuche, Vorschläge wie sie z.B. in Code Complete oder Meyers vorkommen zu beherzigen.
Wie soll ich das jetzt in dem konkreten Fall das umgestalten??
Stream operatoren überladen finde ich aus den genannten Gründen hier ungünstig.
Ich könnte noch die beiden Konvertierungsfunktionen zusammenlegen, aber dann geht "const" bei dem Inputobject verloren, und ich hab ein "if" drin.
Ein zusätzlicher bool-template-parameter würde letztendlich auch in 2 verschiedenen Funktionen (halt mit selben Namen) resultieren, und hätte noch den Nachteil, dass ich für die bool-Spezialisierung alls template-parameter mit spezialisieren müsste.
Mehr Ideen hab ich nicht...Du sagst:
knivil schrieb:
Wenn das so ist, dann gibt es elegantere Methoden in C++
aber ich hab leider keine Ahnung, welche das sein könnten...
Ich verstehe einfach nicht, was ihr jetzt konkret ändern würdet

Ich will nicht um jeden Preis an meinem Design festhalten (insbesondere nicht, da es scheinbar schlecht zu sein scheint), aber ich komm einfach nicht drauf, wie man es besser machen könnte
Darum stelle ich diese nervigen (und scheinbar uneinsichtigen) Fragen...