Klassenteile in versch. Dateien aufspalten
-
Da bin ich mir beim vector noch unschlüssig. Das Ding hat ja eine ganze Menge Methoden, die Datei kommt am Ende sicherlich auf 700-1000 Zeilen. Bei so einer Menge finde ich eine möglichst kurze Klassendefinition (allein mit Methodendeklarationen und 2 Membervariablen schon 87 Zeilen) schon lang genug.
Ich bin am überlegen ob man die hässliche Syntax durch ein oder zwei Makros etwas aufpolieren könnte:
//alte Version: template <class T> typename vector<T>::iterator vector<T>::begin() { return iterator(ptrbegin()); } template <class T> void vector<T>::resize(typename vector<T>::size_type sz, T c = T()) { if (sz <= size()) return; reserve(sz); constructBackN(sz-size(), c); } //neue Version: #define VEC_METHOD(type) \ template <class T> \ type vector<T>:: #define INNER_TYPE_METHOD(type) \ template <class T> \ typename vector<T>::##type vector<T>:: #define DEP_T(type) \ typename vector<T>::#type INNER_TYPE_METHOD(iterator) begin() { return iterator(ptrbegin()); } VEC_METHOD(void) resize(DEP_T(size_type) sz, T c = T()) { if (sz <= size()) return; reserve(sz); constructBackN(sz-size(), c); }so ganz glücklich bin ihc damit aber nicht...
-
@pumuckl:
Also ich hasse solche Makros. Inbrünstig.
Weil sie die Zeit die man braucht um den Code zu lesen (wenn man ihn noch nicht kennt) vervielfachen.
-
hustbaer schrieb:
@pumuckl:
Also ich hasse solche Makros. Inbrünstig.
Weil sie die Zeit die man braucht um den Code zu lesen (wenn man ihn noch nicht kennt) vervielfachen.Wenns zu viele sind durchaus. Wie schon gesagt, glücklich war ich damit nicht.
Mit einer 800-Zeilen Klasse wäre ich aber noch weniger glücklich, und die Syntax der externen definition ist halt hässlich....
-
hustbaer schrieb:
Deswegen bin ich in letzter Zeit auch dazu übergegangen, Klassen-Templates fast ausschliesslich implizit inline zu schreiben.
Ich auch - aber wie pumuckl schon sagt... es ist nicht gerade übersichtlicher dadurch x)
das makro find ich aber auch hässlich... es bringt dir eine zeile pro funktion - also vll 40 zeichen pro funktion - ich würd sie lieber mitschreiben, als mich dann durch makros wühlen zu müssen....bb
-
Darf ich da kurz nochmals nachfragen? Ihr findet sowas hässlich?
////////////////////////////////////////////////////////////////////// // NamedObject template<typename T> class NamedObject { // Typedefs // public: typedef T Type; // Attributes // public: Type m_object; std::string m_name; // Constructors // public: NamedObject(std::string const& name, Type const& object); // Methods // public: Type const& get_object() const; std::string const& get_name() const; }; ////////////////////////////////////////////////////////////////////// // Templates implementation ////////////////////////////////////////////////////////////////////// // NamedObject /********************************************************************/ /* Constructors */ /********************************************************************/ template<typename T> NamedObject<T>::NamedObject(std::string const& name, Type const& object) : m_name(name) , m_object(object) { } /********************************************************************/ /* Methods */ /********************************************************************/ template<typename T> T const& NamedObject<T>::get_object() const { return m_object; } /********************************************************************/ template<typename T> std::string const& NamedObject<T>::get_name() const { return m_name; }Was genau mögt ihr daran nicht? Ich mag nämlich so eine Aufteilung. Gut wir reden hier jetzt über Geschmack, aber es würde mich interessieren, was genau ihr daran nicht mögt

Grüssli
-
Zwei Möglichkeiten: entweder die Klasse ist tatsächlich so kurz, dann sind die diversen Kommentare überflüssig - die Klasse wäre dann übersichtlich genug.

Oder die Klasse ist sehr viel länger, dann hätte man nicht vor drei sondern vor zig Methoden ein
template<typename T> NamedObject<T>::usw. stehen - und die ständige Wiederholung ist halt auch nicht sehr schön.
Vector hat mit Überladungen mal schlappe 40 Methoden, viele haben davon interne typedefs als Rückgabetyp und/oder Parameter, so dass da jedesmal noch eintypename vector<T, Allocator>::iteratoroder ähnliches dazu muss - dann kommen noch die freien Vergleichsfunktionen dazu. Überschlagen sind das 60-80 malvector<T,Allocator>::, 40xtemplate<class T, class Allocator>, 20-40xtypename- nervig!
-
ich hatte doch oben scho nen Beispiel gemacht...
template <typename T> void list<T>::_erase(typename list<T>::node *to_del, typename list<T>::node_base *before, typename list<T>::node_base *after) { assert(to_del && before && after); assert( (to_del != &m.anchor_begin) && (to_del != &m.anchor_end) ); before->next = after; after->prev = before; delete to_del; }ist einfach hässlich -.-
vor allem, wenn ichs auch so machen könnte:
void _erase(node *to_del, node_base *before, node_base *after) { assert(to_del && before && after); assert( (to_del != &m.anchor_begin) && (to_del != &m.anchor_end) ); before->next = after; after->prev = before; delete to_del; }meinste nicht auch? der nachteil liegt natürlich auch auf der hand:
die klasse ist voll mit definitionen und so sind die deklarationen schwerer zu finden...
naja - so, wie es jz aussieht, werd ich es zwar trennen, aber so ganz glücklich damit bin ich eben auch noch nicht... -.-Man sieht ja schon hier:
3x typename
4x list<T>::
1x template <typename T>und das ist nur eine einzige Funktion... -.-
bb
PS: Hab gerad pumuckls Post gesehen(Vorschau) - genau das ist es eben - nervig und unschön - bei mir wäre es eben auch so in etwa...
-
pumuckl schrieb:
Zwei Möglichkeiten: entweder die Klasse ist tatsächlich so kurz, dann sind die diversen Kommentare überflüssig - die Klasse wäre dann übersichtlich genug.

Ich bleibe bei der Darstellung der Klassen einheitlich, deshalb sind die Kommentare bei mir immer vorhanden, egal ob es eine grosse oder kleine Klasse ist

pumuckl schrieb:
Überschlagen sind das 60-80 mal
vector<T,Allocator>::, 40xtemplate<class T, class Allocator>, 20-40xtypename- nervig!Ach, es geht dir hier nur ums schreiben? Da sehe ich keine Probleme, da man sich hier ganz einfache Abhilfe über Copy&Paste schaffen kann, weil es eben immer das gleiche ist. Sowas hat man in ca. einer Minute erledigt, auch bei 60-80 Methoden

1. Man kann die Deklaration der Funktionen kopieren und für die Definition verwenden.
2. Vor die Funktionen muss jeweils zuerst eintemplate<...>und in einem zweiten Durchlauf einClass<...>::. Maus & <Ctrl> + <V> -> zack, zack, zack
3. Zum Teil muss noch eintypename Class<...>::vor den Rückgabewert. Wieder Maus & <Ctrl> + <V> -> zack, zack, zack
4. Ich muss noch meine Kommentare einfügen. Die grobe Unterteilung der Bereiche ist einfach, da habe ich zusätzlich sogar noch Snippets.
Für die Trennung der Methoden, ist es auch immer die gleiche Linie und noch eine neue Linie. Falls ein zusätzliche Abstand noch nicht vorhanden ist, füge ich per <Enter> noch eine ein. Wieder Copy&Paste, dass geht wieder zack, zack, zack
5. Alle Semikolons durch eine neue Zeile und darunter '{' neue Zeile '}' ersetzen lassen. Das ist auch schnell erledigt.
(Edit: 4. und 5. mache ich oft sogar zusammen und füge dann nur noch fehlende neue Zeilen per <Enter> ein ;))@unskilled,
Die Funktionssignatur kannst du kürzen:template<typename T> void list<T>::_erase(node *to_del, node_base *before, node_base *after)Grüssli
-
Oo
Wusst ich noch gar nicht - auf die Idee wär ich auch nich gekommen ^^
Danke : >
-
unskilled schrieb:
Wusst ich noch gar nicht - auf die Idee wär ich auch nich gekommen ^^
Hmmm, vielleicht noch zur Erklärung, wieso das hier geht:
Sobald du mitlist<T>::gesagt hast, wo die Funktion liegt, ist der entsprechende Scope bekannt. Somit wird für die Suche nach den Typen auch der Scope der Klasselist<T>herangezogen.
Das ist auch der Grund, wieso es nicht für den Rückgabetypen geht. Dort ist der Scope der Funktion noch nicht bekannt.
Und das ist einer der Vorteile von C++0x, wo man den Rückgabetypen hinter die Funktionssignatur schreiben können wird, da dort wieder der Scope bekannt ist. In C++0x wird man somit nicht mal mehr beim Rückgabetypentypename list<T>::hinschreiben müssen
Grüssli
-
Danke - fie Erklärung an sich hatte ich jz auch scho ergoogelt ^^
Das Feature des neuen Standards kannte ich noch gar nich - aber hab mich allgemein noch nich so sehr damit beschäfitgt - gibt auch so noch genug, was ich nich weiß

Aber danke noch mal : >bb
-
template <class GreenType, class ShadyBlueType> class FooBarBazQux { public: class State {}; class LaliDo {}; // lieber so ... static boost::shared_ptr<State> FiFaFunction(GreenType green, LaliDo lali); }; // ... oder so? template <class GreenType, class ShadyBlueType> boost::shared_ptr<typename FooBarBazQux<GreenType, ShadyBlueType>::State> FooBarBazQux<GreenType, ShadyBlueType>::FiFaFunction( GreenType green, typename FooBarBazQux<GreenType, ShadyBlueType>::LaliDo lali) { }Ich finde da doch eher die erste Variante "besser"

-
Dravere schrieb:
Ach, es geht dir hier nur ums schreiben?
Nein, es geht NIE ums schreiben, sondern immer ums lesen. Und wenn der Code vollgemüllt ist mit
template<...>,Class<...>undtypename Class<...>::dann machts das Lesen deutlich schwerer.
Ich denke dass die implizit-inline Version dann doch besser lesbar ist - und da man in den meisten IDEs inzwischen soetwas wie ein "collapse all" hat, ists auch nicht schwer, die ganzen Definitionen auf die Funktionssignaturen zu reduzieren.
-
@pumuckl,
Dann könntest du aber das gleiche über die Trennung sagen, wenn es sich nicht um Templates handelt. Man hat auch überall einClass::davor auch vor Rückgabetypen, welche aus der Klasse stammen. Das ganze wiederholt sich auch die gane Zeit und wenn man alles inline machen würde, könnte man mit der IDE durch "collapse all" auch ohne Probleme die reine Deklaration sehen.
Wenn du allgemein der Meinung bist, dass die Trennung unübersichtlich ist, dann versteh ich es zwar nicht, bzw. bin anderer Meinung, kann es aber unter Geschmacksache versorgen.
Wenn du nur Trennung bei Templates als Problem siehst, dann wird in meinem Gehirn einestd::logic_errorException geworfen
@hustbaer,
Du hast unteranderem den gleichen Fehler gemacht, wie unskilled ihn bereits getan hat
Zudem kann man das durchaus auch noch ein wenig besser strukturieren.template <class GreenType, class ShadyBlueType> boost::shared_ptr < typename FooBarBazQux < GreenType, ShadyBlueType >::State > FooBarBazQux<GreenType, ShadyBlueType>::FiFaFunction(GreenType green, LaliDo lali) { }Und mit dem neuen Standard wäre es wohl so, oder? (kenne mich mit der Syntax noch nicht so genau aus:
template <class GreenType, class ShadyBlueType> auto FooBarBazQux<GreenType, ShadyBlueType>::FiFaFunction(GreenType green, LaliDo lali) -> boost::shared_ptr<State> { }Und ja, ich ziehe sowas vor. Vor allem sind solche komplexe Ausdrücke, wie du einen hier präsentierst, eher selten anzutreffen. Und wenn sie vermehrt anzutreffen sind, dann kann man sie meistens durch ein simples
typedefirgendwo oder einer kleinen Hilfstruktur wesentlich vereinfachen.Grüssli