T() oder static_cast<T>() ?



  • Hallo,

    mal eine Frage bezüglich templates, angenommen ich hab so eine Funktion:

    template <typename T>
    void foo(T t) {
        T value1 = T(1); // Variante 1
        T value2 = static_cast<T>(1); // Variante 2
    }
    

    Welchen der beiden Varianten ist der Vorzug zu geben (und warum)?

    Bis jetzt habe ich nämlich immer Variante 1 benutzt, da kürzer und ohne cast. Allerdings hab ich gesehen dass einige Funktionen in boost die zweite Variante benutzen und daher bin ich mir jetzt unsicher.

    Macht das überhaupt einen Unterschied oder ist es nur Geschmacksache?



  • Der functional-cast T() ist für primitive Typen mit dem C-Cast (T) identisch und kann daher mehr als ein static_cast, z.B. Pointer nach int und solche Scherze.


  • Mod

    Welchen der beiden Varianten ist der Vorzug zu geben (und warum)?

    Dass man eine Variable anders initialisiert ist dir hoffentlich klar.

    Angenommen du müsstest einen Ausdruck in einen anderen Typ casten.
    Für T(e) (wobei e ein Ausdruck ist) gelten die folgenden Regeln:

    [expr.type.conv]/1 schrieb:

    If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4).

    Die "corresponding casting expression" ist einfach ein c-style Cast, also (T)e . Und ein solcher Cast ist zum ersten gültigen Cast in der folgenden Liste äquivalent:

    • static_cast
    • static_cast und const_cast
    • reinterpret_cast
    • reinterpret_cast und const_cast

    Daher ist T(e) allgemeiner als static_cast<T>(e) , es kann einen const_cast implizieren und reinterpret_cast anwenden. Und das kann in Template-Code zu Problemen führen - aber auch nur wenn Zeiger im Spiel sind. Solange T ein Klassentyp oder ein arithmetischer Typ ist sind beide Formen äquivalent und T(...) ist vorzuziehen. Und wenn mehrere Ausdrücke als Initializer dienen (bspw. für einen Konstruktoraufruf) kannst du nur functional-style casts verwenden. Wenn ich weiß dass T arithmetisch ist schreibe ich natürlich T(1) . Wozu static_cast ? Ist dasselbe mit mehr Schreibaufwand.



  • Ich bevorzuge static_cast<T>(u) .
    Warum: was Bashar geschrieben hat. Und da die "Macht" des C-Style Casts meist unerwünscht ist...



  • Arcoth schrieb:

    Dass man eine Variable anders initialisiert ist dir hoffentlich klar.

    Warum macht boost dann sowas?

    const value_type a = static_cast<value_type> ( 1 ) / static_cast<value_type>( 2 );
    

    Ich dachte T(x) ruft ganz normal (und ohne cast) den Konstruktor auf, wusste nicht dass das äquivalent tu (T)x ist... das ist natürlich blöd. Warum macht man denn hier so eine Ausnahme für "single expressions"?


  • Mod

    Ich dachte T(x) ruft ganz normal (und ohne cast) den Konstruktor auf, wusste nicht dass das äquivalent tu (T)x ist

    Ja, aber (T)x ist doch für Klassen äquivalent zu static_cast<T>(x) ! Lies meine Posts bis zum Ende durch.

    const value_type a = static_cast<value_type> ( 1 ) / static_cast<value_type>( 2 );
    

    Das ist nicht dieselbe Form wie in deinem Posting. In deinem Post war ein einziger Cast der gesamte Initializer. Hier ist der Initializer ein Ausdruck mit zwei Casts, den kann man natürlich nicht vereinfachen. Allerdings gibt es keinen Grund die Initialisierung in deinem Post zu

    T value1(1);
    

    vereinfachen.

    Warum macht boost dann sowas?

    Höchstwahrscheinlich nutzen die static_cast weil es entweder so in den Richtlinien steht, sie Casts im Code finden wollen ( static_cast ist leicht zu suchen), etc. etc. Hier wird es genau dasselbe wie value_type(1) bewirken.



  • Arcoth schrieb:

    Ja, aber (T)x ist doch für Klassen äquivalent zu static_cast<T>(x) ! Lies meine Posts bis zum Ende durch.

    Schon klar, wie gesagt ich dachte es wäre anders 😉

    Arcoth schrieb:

    Das ist nicht dieselbe Form wie in deinem Posting. In deinem Post war ein einziger Cast der gesamte Initializer. Hier ist der Initializer ein Ausdruck mit zwei Casts, den kann man natürlich nicht vereinfachen.

    Hm Ok.

    Arcoth schrieb:

    Höchstwahrscheinlich nutzen die static_cast weil es entweder so in den Richtlinien steht, sie Casts im Code finden wollen ( static_cast ist leicht zu suchen), etc. etc. Hier wird es genau dasselbe wie value_type(1) bewirken.

    Ok gut, alles klar. Wieder was gelernt 🙂


  • Mod

    happystudent schrieb:

    Schon klar, wie gesagt ich dachte es wäre anders 😉

    Ich verstehe jetzt erst was dein Satz bedeutet: Du wusstest nicht dass T(x) über (T)x und schließlich static_cast den Konstruktor aufruft, sondern direkt. Das habe ich zuerst missverstanden. 🙂



  • Arcoth schrieb:

    Ich verstehe jetzt erst was dein Satz bedeutet: Du wusstest nicht dass T(x) über (T)x und schließlich static_cast den Konstruktor aufruft, sondern direkt. Das habe ich zuerst missverstanden. 🙂

    Kein Problem 🙂


Log in to reply