Formatierung bei Verwendung von STL Funktionen



  • Hallo,
    Ich hab kein direktes Problem, sondern eine Formatierungsfrage. Ich nutze C++ schon relativ lange, allerdings ohne
    die STL wirklich bewusst zu nutzen, das wuerde ich gerne aendern.

    Beim nutzen der Funktionen ist sehr auffaellig, dass die Funktionsaufrufe relativ lang werden. Am meisten wenn man
    zusaetzlich Lambdas verwendet. Ich meine jetzt explizit die Signatur bzw. die Funktionsargumente.

    Habt ihr Tipps zur richtigen Formatierung? Bin bei meiner Recherche auf die Richtlinien von Google gestossen, fand allerdings
    zu dem explizit genannten Fall keine richtige Regel. Ein beispiel waere folgender Code:

      for_each(fininput.begin(), fininput.end(), [&](werte x){
        if(x.start.first == x.ende.first) {
          for_each(next(feld.begin(), x.start.second),
    	       next(feld.begin(), x.ende.second),
    	       [x](vector<int> linie) {
    		 cout << "hello" << endl;
    		 cout << "some code" << endl;
    	       });
        } else { /****/ }
      });
    

    Ueber ein paar Tipps wuerde ich mich freuen.



  • @toobi7007 sagte in Formatierung bei Verwendung von STL Funktionen:

    Habt ihr Tipps zur richtigen Formatierung? Bin bei meiner Recherche auf die Richtlinien von Google gestossen, fand allerdings
    zu dem explizit genannten Fall keine richtige Regel. Ein beispiel waere folgender Code:

    Bei Code-Formatierung gibt es kein "richtig" und "falsch". Nur schön/hässlich und gut/schlecht lesbar. Das ist liegt aber oft im Auge des Betrachters und ist entweder Geschmackssache oder Vorgabe des Projektes, an dem man arbeitet.

    Meine persönliche Präferenz hier ist in Projekten eher weniger verbreitet, ich finde sie allerdings gut lesbar und auch für sehr lange C++-Konstrukte geeignet: Parameter und Terme werden entweder horizontal oder vertikal angeodnet. Niemals gemischt. Das macht m.E. das Lesen leichter, da man mit den Augen nicht hin- und her-scannen, sondern nur in eine Richtung gehen muss. Ausserdem schreibe ich schließende runde Klammern bei vertikaler Anordnung in einer neue Zeile, analog zum } am Ende einer Funktion. Dein Beispiel sähe bei mir so aus:

    for_each(
        fininput.begin(),
        fininput.end(),
        [&](werte x) {
            if (x.start.first == x.ende.first) {
                for_each(
                    next(feld.begin(), x.start.second),
                    next(feld.begin(), x.ende.second),
                    [x](vector<int> linie) {
                        cout << "hello" << endl;
                        cout << "some code" << endl;
                    }
                );
            } 
            else { 
                /****/ 
            }
        }
    );
    

    Argumente für die for_each in Zeilen 1 und 6 werden vertikal angeordnet, da sie nicht in die Zeile passen, die für die next in Zeilen 7-8 allerdings horizontal. Entweder oder. Die Regel wende ich übrigens auch auf if()-terme, klassisches for und sogar auf Template-Argumente an. Damit hab ich bisher selbst bei den irrwitzigsten C++-Ausdrücken noch keine Probleme mit der Zeilenlänge gehabt.

    Auch halte ich bei eigenem Code eine maximale Zeilenlänge von 80 Zeichen ein. Nicht weil ich ein VGA-Textmous-Nostalgiker bin, sondern weil es Untersuchungen gibt, die den "Sweet Spot" zum angenehmen Lesen eines Texts (nicht nur für Code) bei etwa dieser Zeilenlänge verorten.

    Ist aber wie gesagt alles Geschmackssache 😉

    P.S.: Bin übrigens grad ganz happy, dass clang-format das demnächst auch können wird. Dass ich diesen Stil damit nicht spezifizieren konnte, hat mich bisher davon abgehalten, das für meine eigenen Projekte zu verwenden 😕



  • @Finnegan sagte in Formatierung bei Verwendung von STL Funktionen:

    Auch halte ich bei eigenem Code eine maximale Zeilenlänge von 80 Zeichen ein. Nicht weil ich ein VGA-Textmous-Nostalgiker bin, sondern weil es Untersuchungen gibt, die den "Sweet Spot" zum angenehmen Lesen eines Texts (nicht nur für Code) bei etwa dieser Zeilenlänge verorten.

    Quelle? Und wie alt sind die Studien? Mit sind 95 Zeichen (oder auch 100) deutlich lieber. Liegt vielleicht auch daran, dass ich oft lange Variablennamen habe und 4 Zeichen einrücke. Wenn du a = b + c * d nicht mehr innerhalb einer Zeile schreiben kannst (weil die Variablennamen ca 20 Zeichen habe), dann nervt das wesentlich mehr als längere Zeilen.

    Ich meine (auch ohne Quelle) irgendwo gelesen zu haben, dass so um die 100 Zeichen optimal ist, oftmals aus Kompatibilitätsgründen auf 79 beschränkt wird.

    @toobi7007: ich würde
    a) clang-format verwenden und das einfach formatieren lassen (ich mache da immer sowas wie basedonstyle llvm, 95 Zeichen pro Zeile und 4 Indent, aber wie gesagt, kannst du anders machen - am besten außer der Länge nicht viel umkonfigurieren - in Python nehme ich z.B. black, weil das außer der Zeilenlänge praktisch gar keine Optionen hat)

    b) in deinem konkreten Fall hier ist dein Lambda viel zu lang und kompliziert. Ein Lambda mit einem if und darin noch einer Schleife mit Lambda ist einfach nicht mehr gut! Extrahiere den Lambda-Code stattdessen in eine benannte Funktion! Rufe in einem Lambda nur eine Funktion auf, mehr nicht. (ok, ggf auch 2 Funktionen oder ein if und eine Funktion, aber jedenfalls nicht mehr). Dann hast du einen Großteil deines Problems schon gar nicht mehr. Es kann Ausnahmen von dieser Regel geben, aber generell ist die Antwort sehr oft: nicht so tief verschachteln, lieber Funktionen aufrufen.



  • @wob sagte in Formatierung bei Verwendung von STL Funktionen:

    Ich meine (auch ohne Quelle) irgendwo gelesen zu haben, dass so um die 100 Zeichen optimal ist, oftmals aus Kompatibilitätsgründen auf 79 beschränkt wird.

    Gut möglich, dass ich mich da beim runterschreiben vielellicht doch etwas zu weit aus dem Fenster gelehnt habe - da müsste ich auch nochmal nachgucken (falls ich das überhaupt noch finde). Das war zumindest meine Erinnerung an eine überzeugende Argumentation, die ich vor langer Zeit gelesen habe. Kann aber gut sein, dass es mehr waren und die weiteren Überlegungen dann auf 80 Zeichen als Kompromiss kamen.

    Zumindest ist es angenehm, wenn es grob in der Größenordnung liegt 😉

    Wenn du a = b + c * d nicht mehr innerhalb einer Zeile schreiben kannst (weil die Variablennamen ca 20 Zeichen habe), dann nervt das wesentlich mehr als längere Zeilen.

    Ja, so ein "FMA" sollte schon reinpassen. Das Problem hab ich seltener. Ansonsten eben untereinander. Auch hier wende ich die "entweder-oder-Regel"an. Auch wenn das schonmal etwas komisch aussieht:

    result = 
        a
        + very_long_variable_name_1
        - (
            very_long_variable_name_2 
            + very_long_variable_name_2
            + c
        )
        * d;
    


  • Daher lagere ich die Lambdas aus und schreibe sie nie direkt in den Funktionsaufruf:

    std::vector<int> MyVector{ 1, 2, 3, 4 };
    auto f = []( int x ) { return x == 4; };
    if ( std::any_of( MyVector.begin(), MyVector.end(), f ) )
    {
    }
    

    Ich habe eigentlich nie wirklich Probleme mit ausufernden Zeilen...



  • @toobi7007 sagte in Formatierung bei Verwendung von STL Funktionen:

    Habt ihr Tipps zur richtigen Formatierung?

    Bei Lambdas? Nein, Lambdas ergeben eigentlich immer grausig lesbaren Code. Wer sich die Syntax dafür ausgedacht hat, liebt wohl auch Perl. Die STL besteht aber nicht nur aus Lambdas, sondern aus reichlich anderem Code.



  • @It0101 sagte in Formatierung bei Verwendung von STL Funktionen:

    Daher lagere ich die Lambdas aus und schreibe sie nie direkt in den Funktionsaufruf:

    std::vector<int> MyVector{ 1, 2, 3, 4 };
    auto f = []( int x ) { return x == 4; };
    if ( std::any_of( MyVector.begin(), MyVector.end(), f ) )
    {
    }
    

    Ich habe eigentlich nie wirklich Probleme mit ausufernden Zeilen...

    Das kann man so machen, was mich abei jedoch etwas abschreckt ist, dass es sich fast genau so liest wie eine freie Funktion. Da frage ich mich dann schon, warum ich überhaupt eine Lambda verwende:

    auto f(int x) { return x == 4; }
    ...
    if ( std::any_of( MyVector.begin(), MyVector.end(), f ) )
    

    Gut, ich kann als Lambda das Ding direkt kurz vor dem Ort definieren, wo ich es brauche - Funktionen innerhalb von Funktionen gehen ja in C und C++ im Gegensatz zu manchen anderen Sprachen nicht. Aber nur für diese Funktionalität hätte es noch keine Lambdas gebraucht.

    Eine weitere Kritik ist, dass ich bei der Methode ein f im Scope herumschwirren habe und auch die Lebenszeit der Lambda-Funktion eine andere ist. Ich sträube mich ein wenig, eine semantische Änderung ausschliesslich aus Formatierungsgründen einzuführen. Formatierung sollte meiner Meinung nach die Bedeutung des Codes strikt unverändert lassen und ausschliesslich mit Whitespace arbeiten.



  • @Finnegan sagte in Formatierung bei Verwendung von STL Funktionen:

    Eine weitere Kritik ist, dass ich bei der Methode ein f im Scope herumschwirren habe und auch die Lebenszeit der Lambda-Funktion eine andere ist. Ich sträube mich ein wenig, eine semantische Änderung ausschliesslich aus Formatierungsgründen einzuführen. Formatierung sollte meiner Meinung nach die Bedeutung des Codes strikt unverändert lassen und ausschliesslich mit Whitespace arbeiten.

    Da gebe ich dir recht. Dennoch empfinde ich meine Vorgehensweise als geringeres Übel. Unlesbarer Code, der sich eigentlich fast immer ergibt wenn das Lambda erst im Aufruf des <algorithm> erzeugt wird, ist für mich schlimmer als eine leicht verlängerte Lebenszeit einer Variable.


Log in to reply