Stilfrage: T& a oder T &a
-
Tomahawk schrieb:
private: const char* m_token_begin; const char* m_token_end; const char* m_end;+1
Nur dass du das
constauf der falschen Seite voncharstehen hast
-
Wenn man mal den Namen weglässt, sieht eine der beiden Varianten unnötig gequetscht aus:
void (int&, std::string*) void (int &, std::string *)Gerade als Template-Argument geht ein kleines
&oder ein*unter, wenn kein Leerzeichen davor steht.
Beigfinde ich die linke Seite durch den langen Typ sehr unübersichtlich. Für das Sternchen am Ende des Typs muss ich zweimal hinsehen. Wenn es jedoch rechts vom Leerzeichen direkt am Namen steht, sehe ich es sofort.void g(std::vector<int*>::iterator* it); void g(std::vector<int *>::iterator *it);
-
Gutes Argument, TyRoXx. Stimme dir zu. War mir vorher noch gar nicht so bewusst, das mit dem Auffallen.
-
T *fooBegründung für mich:
T* foo, bar; static_assert(std::is_same<decltype(foo), decltype(bar)>::value, "Nope");*, &, && (und bei C++/CLI ^ und
gehören zum Namen, nicht zum Typen.
-
TyRoXx schrieb:
Wenn man mal den Namen weglässt, sieht eine der beiden Varianten unnötig gequetscht aus:
void (int&, std::string*) void (int &, std::string *)Gerade als Template-Argument geht ein kleines
&oder ein*unter, wenn kein Leerzeichen davor steht.
Beigfinde ich die linke Seite durch den langen Typ sehr unübersichtlich. Für das Sternchen am Ende des Typs muss ich zweimal hinsehen. Wenn es jedoch rechts vom Leerzeichen direkt am Namen steht, sehe ich es sofort.void g(std::vector<int*>::iterator* it); void g(std::vector<int *>::iterator *it);verstehe das Argument nicht
void g(std::vector<int *>::iterator *it) // ^ das ist das Templateargument, ein Name folgt nicht void g(std::vector<int *>::iterator *it) // ^ das ist ein Name, aber der Teil davor kein Templateargument/rant/ schrieb:
T *fooBegründung für mich:
T* foo, bar; static_assert(std::is_same<decltype(foo), decltype(bar)>::value, "Nope");*, &, && (und bei C++/CLI ^ und
gehören zum Namen, nicht zum Typen.petitio principii
...Und natürlich gehört const vor den Typ (wo möglich), denn das ist die natürliche Reihenfolge in der Sprache (English), aus der diese Wörter stammen.
-
Mit const stimm ich camper zu. Blöd nur, dass das bei Pointern ungedrejt ist.
Bei mir säh ein Pointer so aus:
const * const T foo;
Heißt das was man liest: konstanter Pointer auf konstantes T.
Was T& angeht, hab ich mich noch nicht entschieden, verwend es mal so, mal so.
-
Typdeklarationen liest man von rechts nach links (und von innen nach außen).
T const * const foo;foo ist ein konstanter Zeiger auf ein konstantes T.
Deshalb schreibe ich es auch so.
-
Nathan schrieb:
const * const T foo;
Das ist kein gültiges C++...

-
Nathan schrieb:
Bei mir säh ein Pointer so aus:
Die Aussage war doch klar:
Wenn es nach Nathan ginge, wär's gültig.
-
Danke, dot, aber ich glaub ich weiß wie man Pointer deklariert.

Man schreibt dazu ein & hinter den Typen.
-
mein stil:
T const& d; T& d; const T d;für mich gehören referenzen usw einfach zum typen (mehrere definitionen in einer zeile sind sowieso das unleserlichste was ich mir vorstellen kann, mach ich nie).
-
Caligulaminus schrieb:
Typdeklarationen liest man von rechts nach links (und von innen nach außen).
T const * const foo;foo ist ein konstanter Zeiger auf ein konstantes T.
Deshalb schreibe ich es auch so.
Das zäumt das Pferd von hinten auf. rechts-nach-links ist lediglich, wie die Deklaration interpretiert wird (auch nur als Faustregel, weil es uns so schwer fällt echt rekursiv zu denken). Gelesen wird nat. trotzdem von links nach rechts (schließlich muss Anfang und Ende erfasst werden), denn der Lesefluss bleibt ja weiterhin rechts-nach-links, oben-nach-unten. Ich kann nicht nachvollziehen, dass diese Umkehrung als natürlich oder einfach empfunden wird. Gewöhnen kann man sich selbstverständlich daran.
Eine Variablendefinition benötigt einen 1. Typ, 2. einen Bezeichner, und 3. einen Initialisierer. Deklaratoren an den Namen anzuflanschen, vermischt 1. und 2. und direkte Initialisierung mittels () oder {} hebt auch noch die Trennung zu 3. auf - was zu zusätzlicher mentaler Arbeit führt, weil diese Teil nicht mehr klar optisch getrennt sind. Von der Tatsache, dass uns die Syntax Fälle aufzwingt, in denen diese Vermischung nicht (einfach) vermieden werden kann, führt allerdings keine Schlussregel, die bestimmt, dass dann auch in allen anderen Fällen so vorgegangen werden sollte.Mehrfachdefinitionen in einer Zeile sind
Antwort an TE: mach, was du willst (ausser Bekehrungsversuchen), nur einheitlich.
-
camper schrieb:
Ich kann nicht nachvollziehen, dass diese Umkehrung als natürlich oder einfach empfunden wird.
C++ ist nicht natürlich, ist technisch. Technik ist künstlich - Kunst.
Ich lese Typdeklarationen von rechts nach links. Das mußte ich mir angewöhnen. Daß ich es akzeptiert und verinnerlicht habe, hat mein Programmierer-Dasein spürbar vereinfacht.
-
camper schrieb:
Mehrfachdefinitionen in einer Zeile sind
Mehrfachdeklarationen in einer Zeile (Funktionsparameter) sind quasi unvermeidbar. Wenn es logisch passt finde ich das sogar empfehlenswert, z.B. iter begin, end;
-
funkyunicoder schrieb:
camper schrieb:
Mehrfachdefinitionen in einer Zeile sind
Mehrfachdeklarationen in einer Zeile (Funktionsparameter) sind quasi unvermeidbar. Wenn es logisch passt finde ich das sogar empfehlenswert, z.B. iter begin, end;
mehrfachdeklarationen in einer zeile bei funktionsargumenten und bei der definition von variablen haben nicht die selbe syntax...
int* a, * b; void f(int* a, int* b) {}
-
Hallo camper,
camper schrieb:
denn der Lesefluss bleibt ja weiterhin rechts-nach-links, oben-nach-unten.
Editiere dies mal, denn du meinst ja "links-nach-rechts"

-
not smart schrieb:
für mich gehören referenzen usw einfach zum typen (mehrere definitionen in einer zeile sind sowieso das unleserlichste was ich mir vorstellen kann, mach ich nie).
Alles außer dem Bezeichner (und dem Initialisierer) gehört in einer Deklaration zum Typ. Insbesondere gehören dazu auch Elemente, die rechts vom Bezeichner stehen, z.B. Array-Klammern und Parameterlisten.
-
funkyunicoder schrieb:
camper schrieb:
Mehrfachdefinitionen in einer Zeile sind
Mehrfachdeklarationen in einer Zeile (Funktionsparameter) sind quasi unvermeidbar. Wenn es logisch passt finde ich das sogar empfehlenswert, z.B. iter begin, end;
Sobald Initializer im Spiel sind, mache ich sofort mehrere Zeilen.
Auch bei Funktionen mache ichdes öfterensehr oft mehrere Parameter in getrennten Zeilen. Wer noch?Eine Variablendefinition benötigt einen 1. Typ, 2. einen Bezeichner, und 3. einen Initialisierer.
Pauschal falsch. Ein Deklarator kann einen Initializer angeben.
Ich habe einen sehr einheitlichen Stil, der von euch aber wahrscheinlich als inkonsistent aufgefasst werden wird. Ich schreibe
T* a; // aber T *a, *b;Das hat nichts mit der Interpretation zu tun - ich sehe direkt, was ein Zeiger ist und was nicht. Ich mag es allerdings, Dinge schön geordnet und in Blöcke zu schreiben. Bei ersterem Fall jedoch tendiere ich einfach (aus Gewohnheit?) dazu, das Asterisk an den Typ zu schreiben.
Tatsächlich impliziert die Regelung von Deklaratoren aber, dass das 'zeiger-sein' zum konkreten Objekt und nicht zum Typ gehört. Das finde ich tatsächlich einfach falsch (wird aber nie mehr korrigiert werden).
Weitere Regeln sind zum Beispiel
constsoweit nach hinten wie möglich. Das hat auch Gründe: Schreibe ich zum Beispielconst class { ... } A;Dann wird ein mancher zuerst verwirrt sein.
Call by reference gibts weder in C noch in C++ noch in Java.
Kannst du das erläutern? Referenzen sind keine Objekte und haben daher auch keine "Werte", daher ist deine Aussage (soweit ich sehe!) völliger Unfug.
-
* und & sind Typkonstruktoren, d.h. angewendet auf einen Typen liefern sie als Ergebnis wieder einen Typen. Sie sind nicht Teil des Namens. Da hilft es auch nicht, mit "bad practise" zu argumentieren, auch wenn es die Syntax erlaubt:
T* a, b;Persoenlich meide ich das.
-
Sone schrieb:
daher ist deine Aussage (soweit ich sehe!) völliger Unfug.

Sone schrieb:
Call by reference gibts weder in C noch in C++ noch in Java.
Kannst du das erläutern?
Man kann kann sich überlegen ob man call by reference oder call by value hat, indem man testet, ob ein naives Swap funktioniert.
template <class T> void naivesSwap(T a, T b){ T c = a; a = b; b = c; } T a = 1, b = 2; naivesSwap(a, b); //geht nichtWenn die Funktion tatsächlich swappt hat man call by reference ansonsten call by value. Wir merken dass wir call by value haben.
template <class T> void naivesSwap(T *a, T *b){ T c = *a; *a = *b; *b = c; } T a = 1, b = 2; naivesSwap(&a, &b); //gehtMan könnte jetzt argumentieren, dass wir jetzt call by reference haben. Schließlich übergeben wir ja &a <=> Adresse von a <=> Zeiger auf a <=> Referenz auf a. Ich würde dagegen halten, dass wir ja gar kein T by reference übergeben, sondern ein T* by value.
template <class T> void naivesSwap(T &a, T &b){ T c = a; a = b; b = c; } T a = 1, b = 2; naivesSwap(a, b); //gehtGenauso wie bei den Pointern könnte man argumentieren, dass direkt a und b übergeben werden. In der Funktion steht, dass man gern ein T & <=> T als Referenz haben möchte. Ich hingegen würde sagen es wird wieder kein T als Referenz übergeben, sondern ein T & als Wert. Beim Aufruf naivesSwap(a, b) stellt der Compiler fest, dass er ein T mit einem T & matchen soll. Er konvertiert/generiert ein T & aus einem T, damit die Funktion überhaupt aufrufbar ist. Ich übergebe also gar kein T, sondern ein T&.
Je mehr ich darüber nachdenke, desto mehr finde ich, dass beide Ansichten dasselbe mit anderen Worten beschreiben. Ich finde aber die call by value-Sicht einfacher, denn sie hat einfachere Regeln. Immer call by value, keine Ausnahme. Mal call by reference und mal call by value ist schwer, insbesondere weil man bei T * immer verwirrt ist welches es nun ist, insbesondere wenn T ein Pointer ist.
Sone schrieb:
Referenzen sind keine Objekte und haben daher auch keine "Werte"
Referenzen sind genauso "Objekte" wie Pointer auch. Sie sind keine Objekte im Sinne von Klassen, aber sie sind Objekte im Sinne von Builtin-Typen. Und sie haben natürlich einen Wert, nämlich das Objekt, dass sie Referenzieren. Sonst wären ja alle Referenzen identisch.