optionale const reference auf nullptr setzen funktioniert, aber warum?



  • SeppJ schrieb:

    Dann viel Spaß, wenn du demnächst überall if(pointer != nullptr) schreibst, anstatt if(pointer) .

    Huch?
    if (pointer) wäre doch bloss ein Problem wenn typeof(pointer) == nullptr_t . Also vermutlich nur innerhalb von Templates, wieso sonst sollte man ne Variable vom Typ nullptr_t machen und dann explizit gucken ob sie denn null ist?
    Also schon nervig aber nicht MEGA-nervig.

    Und davon abgesehen, um es zu erlauben hätte auch ein expliziter operator bool gereicht ( if (expression) gilt ja als explizite Konvertierung nach bool).

    Bin also auch etwas überrascht dass hier implizit konvertiert wird.

    Oder steh ich grav vollkommen auf dem Schlauf 😕


  • Mod

    Was SeppJ wohl meinte: "Die Konvertierung von nullptr nach bool funktioniert weil nullptr in einen Zeiger konvertiert werden kann [das ist falsch, denn dann wäre die Konvertierung mehrdeutig], und die konvertieren nach bool . Wenn letzteres verboten wird, dann funktioniert if (ptr) nicht mehr."


  • Mod

    hustbaer schrieb:

    Und davon abgesehen, um es zu erlauben hätte auch ein expliziter operator bool gereicht ( if (expression) gilt ja als explizite Konvertierung nach bool).

    Bin also auch etwas überrascht dass hier implizit konvertiert wird.

    Ich nicht. Warum sollten sich null pointer values und pointer unterschiedlich benehmen, wenn ich sie einem bool zuweise? Gerade das wäre verwirrend.


  • Mod

    C++14 präzisiert, dass die Konvertierung nur im Kontext einer Direktinitialisierung zulässig ist (wobei die genaue Bedeutung dieser Regel auch nicht völlig glasklar zu sein scheint #1781).

    Kurzer Test mit g++ (5.4.0,6.3.0,7.1.0): verweigert die Konvertierung für -std=c++11 und -std=c++14 und -std=c++17
    clang 4.0.0: führt die Konvertierung durch für alle Versionen, warnt aber auch in allen Fällen.


  • Mod

    Hmm. Im Nachhinein macht es doch Sinn. Schließlich war einer der motivierenden Gründe overload resolution:

    void f(bool);
    void f(int*);
    
    f(nullptr); // call #2
    

    Implizite Konvertierung nach bool würde zumindest dieses Beispiel brechen.


  • Mod

    Arcoth schrieb:

    Hmm. Im Nachhinein macht es doch Sinn. Schließlich war einer der motivierenden Gründe overload resolution:

    void f(int);
    void f(int*);
    
    f(nullptr); // call #2
    

    Implizite Konvertierung nach bool würde alle arithmetischen Typen mit sich ziehen. In diesem Beispiel wäre das egal, weil die zweite SCS in der UCS für #1 schlechter wäre (Promotion statt Identität). Aber es wäre trotzdem nicht gewollt, dass nullptr das Verhalten aufweist.

    Eine Standardkonvertierungssequenz kann nur maximal eine "richtige" Konvertierung haben (der Kram, der gleich am Anfang des Kapitels (jetzt 7 Standard Conversions) steht).
    nullptr_t->bool->int geht nicht in einer einzigen Sequenz.


  • Mod

    Ja, ich hatte zu pragmatisch gedacht; nullptr_t ist keine Klasse. Allerdings hast du den Edit verpasst. :p


  • Mod

    Wenn mich mein Geächtnis nicht täuscht, war u.a. auch genau dieses Beispiel eines, um motivierend zu zeigen, warum nullptr_t als Klasse nicht funktioniert (um NULL zu ersetzen), und direkte Unterstützung durch den Sprachkern erforderlich ist. Wer Lust hat, kann sich ja das entsprechende Paper zu Gemüte führen, ist ja nur ein paar Klicks entfernt.


  • Mod

    camper schrieb:

    Wenn mich mein Geächtnis nicht täuscht, war u.a. auch genau dieses Beispiel eines, um motivierend zu zeigen, warum nullptr_t als Klasse nicht funktioniert (um NULL zu ersetzen), und direkte Unterstützung durch den Sprachkern erforderlich ist.

    Weil explizite Konvertierungsoperatoren nicht standardisiert waren? Oder weil ein Konvertierungsoperator-Template in overload resolution einem non-template Konverierungsoperator per se unterliegt? Ich frage mich, ob man letzteres durch ein Template mit default argument lösen könnte.


  • Mod

    Arcoth schrieb:

    camper schrieb:

    Wenn mich mein Geächtnis nicht täuscht, war u.a. auch genau dieses Beispiel eines, um motivierend zu zeigen, warum nullptr_t als Klasse nicht funktioniert (um NULL zu ersetzen), und direkte Unterstützung durch den Sprachkern erforderlich ist.

    Weil explizite Konvertierungsoperatoren nicht standardisiert waren? Oder weil ein Konvertierungsoperator-Template in overload resolution einem non-template Konverierungsoperator per se unterliegt? Ich frage mich, ob man letzteres durch ein Template mit default argument lösen könnte.

    u.a. Das Problem mit NULL wurde ja schon diskutiert, bevor C++ überhaupt standardisiert wurde.
    Nachdem ich nochmal die entsprechenden Teile rausgesucht habe (N2431 #654 N2656), muss ich feststellen, dass ich mich wahrscheinlich getäuscht habe. Eventuell habe ich das mit einer Diskussion über bool-Konvertierungen für Smartpointer verwechselt (bevor es explizite Konvertierungsoperatoren gab) - da war es so dass dieser unspecified-bool am Besten (die beste Variante von mehreren schlechten Lösungen, wohlgemerkt) ein Zeiger auf Member(funktion) ist, damit nicht so komische Sachen wie:

    smart_ptr p;
    p*42;
    

    möglich sind.



  • SeppJ schrieb:

    Dann viel Spaß, wenn du demnächst überall if(pointer != nullptr) schreibst, anstatt if(pointer) .

    Auch wenn das nicht deine Welt ist: Bin kein Freund von impliziten Typumwandlungen und schreibe so etwas tatsächlich meist explizit aus - obwohl mir
    die impliziten Umwandlungen bekannt sind und ich weiss dass es nicht nötig wäre. Vorteil: Im Zweifelsfall lässt sich direkt aus dem Code ablesen, dass die
    Umwandlung so gewollt war und sich jemand Gedanken darüber gemacht hat. Weniger schreiben zu müssen empfand ich beim Programmieren noch nie als
    großen Vorteil, da zumindest bei mir die meiste Zeit nicht fürs Tippen draufgeht 😉


Anmelden zum Antworten