Wer ist auf die idee gekommen…

…dass es eine gute idee sei, dass der folgende ausdruck in C++ legal sein soll:

extern int a, b, c, x, y;
(x == y ? a : b) = c;

Ich befürchte schlimmes. Diese formulierung einer… ähm… zuweisung mit bedingtem ziel ist so dermaßen hirnkitzelnd, missverständlich und gaga, das werden leute auch machen. Übrigens hätte man so etwas auch vorher schon in C machen können, wenn man es nur ein bisschen expliziter geschrieben hätte, indem man an einen dereferenzierten pointer zuweist:

#include <stdio.h>
int main (int argc, char **argv)
{
  int a = 1, b = 2, c = 3, x = 4, y = 5;
  *(x == y ? &a : &b) = c;
  printf ("a = %d; b = %d; c = %d\n", a, b, c);
  return 0;
}

Ich musste wirklich ausprobieren, ob das geht, weil ich noch nie auf die idee gekommen bin, eine derartige zeile zu schreiben. Der kompeiler gibt mit -Wall nicht einmal eine warnung… 😁️

Und b wird tatsächlich auf 3 gesetzt, weil 4 != 5 ist. Warum das keiner jemals so gemacht hat? Weils im hirn kitzelt, missverständlich und gaga ist. Aber unter C++-proggern scheint die zeit für so etwas reif zu sein. Da ist das standard. Ohne diese adress- und dereferenzierungs-operatoren, die etwas klarer machen, was hier abgeht, sondern schnell, einfach und direkt, wie jugendliche bei ihren ersten sexuellen erfahrungen:

#include <iostream>
int main (int argc, char **argv)
{
  int a = 1, b = 2, c = 3, x = 4, y = 5;
  (x == y ? a : b) = c;
  std::cout << "a = " << a << "; b = " << b << "; c = " << c << std::endl;
  return 0;
}

Wer ist nur auf die idee gekommen, dass das eine gute idee sei? Verkauft den typen an die chinesen! Das ist die beste sabotahsche…

11 Antworten zu “Wer ist auf die idee gekommen…

  1. Das war schon in Perl so. man perlop und dann /Conditional Operator.

    Hat mich übrigens nie gestört. Allerdings fällt mir auch nur ein einziges „cooles“ Anwendungsbeispiel ein: Binäre Suche, wobei man in jedem Schritt entweder die Ober- oder die Untergrenze auf die Mitte setzt. Aber STL-Kenner nehmen dafür natürlich std::lower_bound.

    Noch ein Hirn-Twist: Ein von einer Funktion zurückgeliefertes Klassenobjekt (als Wert) kann modifiziert werden (also non-const-Member-Funktionen ausführen). Zu Zeiten von C++03 war das noch nützlich, da konnte man ein paar temporäre Allokationen einsparen. Seit C++11 mit der Move-Semantik ist das nicht mehr angesagt. Wen so etwas grundsätzlich stört, der kann ein & hinter die Parameterliste der Member-Funktion schreiben. Dann „bindet“ sie nur noch an Lvalues, nicht mehr an Xvalues.

    Explizite Schleifen und ++ und dergleichen sind in meinen Bibliotheken selten geworden. Mit der STL und mit ranges ist der Kode verständlicher und wird letzlich in den gleichen Maschinenkode übersetzt.

    Nehmen wir mal an, Du willst so etwas:

    std::valarray
        a{0.,8.,1.,5.}, b{4.,7.,1.,1.}, c(4);
    c = a * 3.14 + b;

    Aber dummerweise sind a, b, c nicht std::valarray, sondern std::vector. Wie umschreiben?

    Mit Eric Nieblers range-v3 geht das so:

    using ranges::zip;
    for(auto&& [a_, b_, c_]: zip(a, b, c))
        c_ = a_ * 3.14 + b_;

    Man kann an zip-Elemente zuweisen! Kein Sternchen++ mehr nötig. Obendrein verkürzt das zip die Schleife automatisch auf die Länge der kürzesten Folge. Kein versehentlicher Buffer-Overflow mehr.

    Was wirklich gaga ist: Die syntaktische Ausnahme, wann der C++-Compiler etwas als universelle (Forwarding) Referenz statt als Rvalue-Referenz interpretiert. Hätte das Komitee nicht einfach &&& nehmen können?

    • Hups, dein HTML-Sanitizer hat ein Template-Argument <double> unterschlagen…

      Wie wär’s mit Markdown für Kommentare? Am Besten gleich mit LaTeX-Formel-Unterstützung…

      • Das hier ist leider ein wordpress. 😉

        Hier schreibt man &lt; für < und &gt; für >. Ich weiß gar nicht, ob man im selbstgehosteten wordpress noch markdown freischalten kann, hier bei wordpress.com gehts so weit ich weiß nicht.

        Aber dafür kann man hier bei wordpress.com LaTeX schreiben, was ich gar nicht so sinnlos finde. Einfach wie gewohnt zwischen dollarzeichen:

        $\intop_{a}^{b}f(x)\,\mathrm{d}x=F(b)-F(a)$

    • Kleine Korrektur: ranges::views::zip.
      Header: #include <range/v3/view/zip.hpp>.
      Der Autor hält das Schema so wie die Leute von boost.org.

      Wenn Du das ausprobieren willst und überrascht feststellst, dass == bei valarray keinen bool zurückliefert, sondern ein valarray<bool>: Das Vorbild dafür kommt von den Matlab-ähnlichen Sprachen (Scilab, Octave, FreeMat, …). Abhilfe mit ranges::all_of oder gleich ranges::equal.

  2. Wo wir gerade bei Hirnkitzel sind: Es gibt da ja den alten C-Trick eines uminterpretierenden Casts:

    *(neuer_typ*)(&ding_mit_altem_typ)

    Das gibt übrigens nicht immer Undefined Behavior: Man darf z.B. einen struct auf den Typen seines ersten Eintrags casten, das ist portabel.

    In C++ wollen wir das natürlich etwas schöner und ordentlicher ausdrücken, und tatsächlich kann man sich die Sternchen mittels Referenzen sparen:

    reinterpret_cast)(ding_mit_altem_typ)

    Außer natürlich, wenn ding_mit_altem_typ ein Rvalue ist. Dann würde die C-Version gar nicht funktionieren. In der C++-Variante schreibt man einfach && statt &. Wieder was gewonnen.

    Detail am Rande: Wer mit Microsofts Visual Studio bis 2017 geschädigt ist, kriegt Casts mit Rvalues manchmal falsch oder gar nicht kompiliert. Da muss man das in ein explizites std::forward oder std::move packen, damit der Compiler einem glaubt, dass man jetzt ehrlich und ohne Scheiß eine Rvalue-Referenz haben will. Ab VS2019 geht es anscheinend.

    • Gegen die casts von C++ werde ich niemals etwas sagen. Die sind deutlich, machen klar, wo möglicherweise ein problemchen auftauchen könnte und sind nicht wie die ollen C-casts ein bisschen kryptisch. Das kann meinetwegen auch gern in C zurückübernommen werden. 😉

      Oh, ich sage das lieber nicht so laut, sonst habe ich gleich einen mob hinter mir.

  3. Wenn man schimpfen will, könnte man fragen, wer eigentlich geglaubt hat, es sei eine gute Idee, in C++ einen benutzerdefinierten Komma-Operator und Adress-Operator (unäres &) zu erlauben.

    Herb Sutter würde ja gerne noch den Punkt-Operator überladen können. Hoffentlich hält ihn jemand auf.

    • Herb Sutter würde ja gerne noch den Punkt-Operator überladen können

      Warum? Will der für den operator. etwa ein anderes objekt zurückgeben, dessen element oder metode dann verwendet wird? Großartige idee. Den müssen wir auch an die chinesen verkaufen!

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.