Sone (Hacker) erklärt die Welt (C++11). War: C++ auto



  • @pumuckl: GCC ist doch viel weiter vorn als MSVC, das weißt du doch 🙄

    Das ganze (+ decltype ) nennt sich automatic type deduction (engl. für automatische Typ-Deduzierung), falls der TE es wissen möchte.

    1. Wann würdet ihr "auto" verwenden?

    Wann immer möglich.

    Dem kann ich leider nicht ganz Zustimmen. Mir ist es gerade bei APIs oder Libs in die ich einsteige sehr wichtig, zu sehen, welchen Typ mir eine Funktion gegeben hat:

    auto system = createLODAnimationState(mAnimPtr);//So eine Funktion macht natürlich wenig Sinn, aber es geht um den Namen
    

    hier könnte ich unmöglich erkennen, welche Klasse zurückgegeben wird ➡ ich muss entweder daneben schreiben, welchen Typ system jetzt hat oder jedes mal die API-Referenz aufsuchen ⚠

    Oder ich schreibe einfach, weil ich nicht so faul bin, Zehn oder 15 Zeichen dahin und habe was ich will.

    Also bei Standardbibliotheks-Membermethoden oder -Funktionen gerne, aber nicht bei fremden Zeug.

    Mit aller Sicherheit hab ich aber hier einen Denkfehler, und zig Leute werden mir jetzt erklären warum meine Erklärung doof war 😃 .

    Edit:

    Explizite initialisierung

    Das heißt, eine Variable gleich mit einem Funktions-Rückgabewert initialisieren?



  • Die Argumentation leuchtet mir nicht ein. Wenn du

    foo(bar());
    

    schreibst, machst du dir auch keine Gedanken darum, was bar zurückgibt, solange es in foo passt. Ob du jetzt in der Dokumentation erst die Funktion oder gleich den Typ nachschlägst, ist letztendlich egal.



  • Sone schrieb:

    Mit aller Sicherheit hab ich aber hier einen Denkfehler, und zig Leute werden mir jetzt erklären warum meine Erklärung doof war 😃 .

    Naja, bei Visual Studio kann man mit der Maus über die Funktion drüberfahren und mit etwas Glück sieht man die Signatur und den Rückgabewert. Aber generell geb ich dir schon Recht. "auto" ist zwar meist etwas schneller zu schreiben, aber sonst ist es besser lesbar.



  • seldon schrieb:

    Die Argumentation leuchtet mir nicht ein. Wenn du

    foo(bar());
    

    schreibst, machst du dir auch keine Gedanken darum, was bar zurückgibt,

    Ist dein Beispiel dasselbe wie das meinige? Nein. In meinem wird ein Funktionsrückgabewert als initializer verwendet.

    Was ich spezifischer meine sind auch alte Codes, die man sich ansieht.

    Ogre::Vector3 foo = mCamera->getRayForwardIntersect(anch, &dir, offset);
    

    Sogar hier kann ich schon nur den Sinn dieser Metasyntaktischen (oder später auch normalen lokalen) Variable durch den Kontext erkennen. Vielleicht gibt getRay...() ja auch einen Skalar zurück, usw., auto da zu benutzen macht für mich Null Sinn.



  • Sone schrieb:

    Vielleicht gibt getRay...() ja auch einen Skalar zurück, usw.,

    Nen ziemlich eindimensionaler Ray.



  • Mechanics schrieb:

    Sone schrieb:

    Mit aller Sicherheit hab ich aber hier einen Denkfehler, und zig Leute werden mir jetzt erklären warum meine Erklärung doof war 😃 .

    Naja, bei Visual Studio kann man mit der Maus über die Funktion drüberfahren und mit etwas Glück sieht man die Signatur und den Rückgabewert.

    Mit Intellisense, unter MSVC, habe ich leider mittelgute bis unausreichende Erfahrung gemacht.



  • cooky451 schrieb:

    Sone schrieb:

    Vielleicht gibt getRay...() ja auch einen Skalar zurück, usw.,

    Nen ziemlich eindimensionaler Ray.

    Das war ein Beispiel, du alter S***. 🙄



  • Sone schrieb:

    Das war ein Beispiel, du alter S***. 🙄

    Jup, und dennoch steckt ein Stückchen Wahrheit drin: Bei den meisten Funktionen sagt der Name schon in etwa, was sie zurückgeben, wie z.B. hier, dass es eben kein Skalar ist. Wenn man die Variable jetzt nicht foo nennt sondern einen passenden Namen vergibt, dann ist der auch aussagekräftig genug, um in etwa auf den Typ schließen zu können. Die grobe Typkategorie (Container von irgendwas, Iterator, mehrdimensionaler Vector usw.) kann man normalerweise gut im Namen der Variablen ausdrücken, den exakten Typ braucht man normalerweise nicht zu wissen - dafür ist auto eben gut.

    Sone schrieb:

    @pumuckl: GCC ist doch viel weiter vorn als MSVC, das weißt du doch 🙄

    Dass er das grundsätzlich ist weiß ich. Ob das auch bei jedem einzelnen Feature so ist, das im MSVC11 umgesetzt wurde, hab ich "versäumt" nachzulesen.



  • Kóyaánasqatsi schrieb:

    Hallo,
    ich habe das Schlüsselwort "auto" eigentlich nie gebrauchen müssen, allerdings würde ich gerne wissen, wann man es verwenden, und wann nicht, sollte.

    Hier kannst du noch sehen, was Herb Sutter dazu sagt. (Minute 16 bis Minute 23)



  • Naja, der Name, der Name... ob ich jetzt den Namen lang hab oder den Typ ist doch wurscht.



  • Sone schrieb:

    Naja, der Name, der Name... ob ich jetzt den Namen lang hab oder den Typ ist doch wurscht.

    Nope. Der Name sollte aussagekräftig sein. auto ist nicht dazu gedacht, dir Tipparbeit zu sparen, sondern es ist dazu gedacht, redundante Typangaben zu vermeiden. Dass man dadurch oft auch Tipparbeit spart ist nur ein netter Nebeneffekt.



  • Du meinst, die Typangabe ist insofern redundant, da man sich den Typ auch ungefähr vom Namen oder dem Initializer her ableiten kann. Gut, gut, da hast du Recht.

    Trotzdem wirst du mir zustimmen dass das höchstens bei Klassen gut ist, weil es recht bescheuert wäre (laut deiner Logik aber sinnvoll da es eine redundante Typangabe ist!)

    auto a(4);//das anstatt
    int a(4); //dem zu schreiben
    auto b = {1, 2, 5, 8};//Ist das jetzt eine Initializerlist oder ein C-Style Array?
    int b[] = {1, 2, 5, 8};//Keine Frage
    


  • pumuckl schrieb:

    auto ist nicht dazu gedacht, dir Tipparbeit zu sparen, sondern es ist dazu gedacht, redundante Typangaben zu vermeiden.

    Das würde ich anders formulieren. Und im Motivationsabschnitt des auto-Proposals tauchen sicherlich auch extrem lange Iterator-Typen auf, die man nicht wirklich hinschreiben will. Um das Sparen von Tipparbeit geht's also auch. Bei "redundante Typangaben" fällt mir spontan nur

    auto sp = make_shared<Thing>(42);
    

    ein, wo es klar sein sollte, dass sp ein shared_ptr<Thing> ist. Aber oft weiß man den Typ ja gar nicht genau (z.B. Lambdas, std::bind-Ergebnis u.s.w.). auto erlaubt da auch ein besseres generic programming:

    template<class T>
    void show(T const& c)
    {
      auto it = begin(c);
      auto ee = end(c);
      // Was ist decltype(it)? Keine Ahnung
      // Ggf gibt es den Typ T::const_iterator
      // Ggf auch nicht (bei rohen Arrays)
      while (it!=ee) {
        cout << *it << ' ';
        ++it;
      }
    }
    

    auto eilt also zur Hilfe, wenn man den Typen nicht explizit hinschreiben will oder kann.

    Ich weiß aber auch noch nicht, wie schlau es ist, auto auch dann einzusetzen, wenn ich den Typen auch selbst kurz hätte hinschreiben können. Ich denke, wenn vom Kontext nicht klar ist, was für eine Art von Typ eine "auto-Variable" hat, dann macht man es dem Leser eventuell unnötig schwer, das Programm nachzuvollziehen. Aber irgendwie arrangieren sich die Nutzer von dynamischen Sprachen ja auch damit, in denen ganz selten mal Typen explizit genannt werden -- wobei mich das aber eigentlich ein bisschen stört.



  • Sone schrieb:

    auto a(4);//das anstatt
    int a(4); //dem zu schreiben
    auto b = {1, 2, 5, 8};//Ist das jetzt eine Initializerlist oder ein C-Style Array?
    int b[] = {1, 2, 5, 8};//Keine Frage
    

    Suuuuper Beispiele, ganz grosses Kino, nein ... wirklich ...


  • Mod

    Sone schrieb:

    auto a(4);//das anstatt
    int a(4); //dem zu schreiben
    auto b = {1, 2, 5, 8};//Ist das jetzt eine Initializerlist oder ein C-Style Array?
    int b[] = {1, 2, 5, 8};//Keine Frage
    

    Mir fehlt da noch ein

    auto c[] = { 2, 3, 5 };
    

    .. kommt ja vielleicht mit dem nächsten Standard.



  • knivil schrieb:

    Sone schrieb:

    auto a(4);//das anstatt
    int a(4); //dem zu schreiben
    auto b = {1, 2, 5, 8};//Ist das jetzt eine Initializerlist oder ein C-Style Array?
    int b[] = {1, 2, 5, 8};//Keine Frage
    

    Suuuuper Beispiele, ganz grosses Kino, nein ... wirklich ...

    ??? Was zum Teufel war daran jetzt schlecht? Bei Skalaren ist es doch wirklich ein wenig unnötig, den Typ anhand des Literals o. ä. deduzieren zu lassen. Eben so bei C-Arrays. Das wollte ich damit nur sagen.



  • #include <vector>
    #include <tuple>
    
    int main (){
        std::vector<std::tuple<std::string,std::string,std::string>> v;
        std::vector<std::tuple<std::string,std::string,std::string>>::const_iterator it=v.cbegin();
        auto it2=v.cbegin();
    }
    

    Will man ernsthaft sowas tippen?

    Für einfache ints ist es aber unnötig.. Da habt ihr schon recht.



  • std::vector<std::tuple<std::string,std::string,std::string>>
    

    Wer zum Teufel hat so einen Container? 😃
    Dann würde ich mir schon eine Datenstruktur schreiben.



  • Sone schrieb:

    auto b = {1, 2, 5, 8};//Ist das jetzt eine Initializerlist oder ein C-Style Array?
    

    Falls das eine ernste Frage war: decltype(b) wird std::initializer_list<int> sein.



  • krümelkacker schrieb:

    Sone schrieb:

    auto b = {1, 2, 5, 8};//Ist das jetzt eine Initializerlist oder ein C-Style Array?
    

    Falls das eine ernste Frage war: decltype(b) wird std::initializer_list<int> sein.

    Sowas liebe ich: quasi zitiert, aber so tun, als ob dass Allgemeinwissen sei, und jeder wissen müsste.

    C++11 schrieb:

    7.1.6.4 auto specifier
    6 Once the type of a declarator-id has been determined according to 8.3, the type of the declared variable using the declarator-id is determined from the type of its initializer using the rules for template argument deduction. Let T be the type that has been determined for a variable identifier d. Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list (8.5.4), with std::initializer_list<U>. The type deduced for the variable d is then the deduced A determined using the rules of template argument deduction from a function call (14.8.2.1), where P is a function template parameter type and the initializer for d is the corresponding argument. If the deduction fails, the declaration is ill-formed. [ Example:
    ` auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>

    auto x2 = { 1, 2.0 }; // error: cannot deduce element type`
    —end example ]

    Wenig glanzvoll, lieber krümelkacker.


Anmelden zum Antworten