Warum using bei Template-Alias (C++0x)?



  • Ich frage mich schon länger, warum man bei den Template-Aliases in C++0x using statt typedef als Schlüsselwort verwendet hat. In alle Quellen, die ich gefunden habe, ist nur sehr ungenau von "technischen Gründen" oder "es ist nicht gelungen, eine konsistente Syntax zu finden" die Rede.

    Kurz und Knapp, meine Idee wäre folgende gewesen:

    //statt
    template<class T>
    using Vec = std::vector<T,My_alloc<T>>;
    
    // mit typedef
    template<class T>
    typedef std::vector<T,My_alloc<T>> Vec;
    

    Natürlich bin ich mir aber sicher, dass die Leute des Kommitees darauf auch gekommen sind, die Idee aber wegen ewaiger Ungereimtheiten verworfen haben.
    Genau diese Ungereimtheiten interessieren mich. Ich übersehe da sicher irgendwelche Spezialfälle, bei denen diese Syntax nicht funktioniert, es wäre nett, wenn ihr mir genau diese nahelegen könntet.



  • och, dieses typedef is generell gewöhnungsbedürftig. ich find's gar nicht übel, dass using typedef komplett ersetzen kann jetzt:

    using foo = double;
    

    geht jetzt auch. Hurrah, Konsistenz! 🙂

    Man kann auch sofort sehen, was da passiert:
    neuer_name = typ
    (bei komplizierteren Beispielen merkt man dann den Vorteil)

    typedef int*(*bar)(int);
    // oder
    using bar = int*(*)(int);
    

    Genaue Gründe kenne ich auch nicht.



  • och schrieb:

    Hurrah, Konsistenz! 🙂

    👍

    och schrieb:

    (bei komplizierteren Beispielen merkt man dann den Vorteil)

    👍

    och schrieb:

    Genaue Gründe kenne ich auch nicht.

    Ich kann zur Not damit leben, nicht zu erfahren, warum nicht. 🤡



  • och schrieb:

    ich find's gar nicht übel, dass using typedef komplett ersetzen kann jetzt:

    using foo = double;
    

    geht jetzt auch. Hurrah, Konsistenz! 🙂

    Für diverse Sprachmittel eine Alternativmöglichkeit einzuführen, obwohl die bisherigen ihren Dienst gut geleistet haben, ist nicht gerade der Inbegriff von Konsistenz. Ich glaube auch nicht, dass sich die Vision von einheitlichem Sprachmittelgebrauch durchsetzen wird. Dafür ist es in C++ zu spät. Ich befürchte eher, man könnte mit diesem Vorgehen das genaue Gegenteil erreichen, weil sich Codestile noch stärker unterscheiden werden.

    Ich bin da grundsätzlich skeptisch. Konsistenz ist bestimmt nicht der richtige Ausdruck.

    // Alles Initialisierungen für int mit Wert 5
    int a(5);
    int a{5};
    int a = {5};
    int a = 5;
    
    std::complex<float> c(7); // Konstruktoraufruf mit einem Parameter
    std::complex<float> c{7}; // Konstruktoraufruf mit einem Parameter
    std::vector<float> v(7); // Konstruktoraufruf mit einem Parameter
    std::vector<float> v{7}; // Initialisierungsliste mit einem Element 7
    

    Soviel zur Einheitlichkeit. Funktionssyntax ist auch sowas (für Spezialfälle braucht man die neue Syntax, ja). An anderen Orten wird dafür krampfhaft recycelt und versucht, imaginäre Sprachzusammenhänge zu suggerieren.

    MyClass() = default;
    MyClass(const MyClass&) = delete;
    
    enum class MyEnum {};
    

    Furchtbar. Was diesen Teil von C++0x betrifft, bleibt mir nicht viel mehr als 👎 übrig. Zum Glück gibts Features, auf die man sich freuen kann.



  • Nexus schrieb:

    MyClass() = default;
    MyClass(const MyClass&) = delete;
    
    enum class MyEnum {};
    

    Ähh das Erste kannte ich...und hielt es irgendwie für sinnvoll.

    Aber was soll bitteschön das zweite sein? //edit: bedeutet das: der copy-ctor ist nicht vorhanden?

    Und das Dritte?

    //edit
    Ich glaube das Problem bei Typedef ist, dass Typedef einen Typen beschriebt. Ein Template-alias ist aber kein Typ. Es ist nur etwas, was irgendwann mal ein Typ werden könnte. Deswegen wäre Typedef inkonsistent.





  • Nexus schrieb:

    och schrieb:

    ich find's gar nicht übel, dass using typedef komplett ersetzen kann jetzt:

    using foo = double;
    

    geht jetzt auch. Hurrah, Konsistenz! 🙂

    Für diverse Sprachmittel eine Alternativmöglichkeit einzuführen, obwohl die bisherigen ihren Dienst gut geleistet haben, ist nicht gerade der Inbegriff von Konsistenz.

    Nun, aus irgend einem technischen Grund gibt's kein templatisiertes typedef. Man hat daher diese using-Syntax benutzt. Mit Konsistenz meine ich, dass diese using-Syntax auch für "normale typedefs" herhalten kann.

    Von dem initializer_list-Kram bin ich auch nicht gerade begeistert. Ich sehe da bis heute noch keine Verwendung für -- außer in kleinen (IMHO) praxisfernen Code-Beispielen wie

    int main() {
      map<string,string> telefonbuch = {
        {"Oskar", "12345"},
        {"Wilhelm", "54321"}
      };
    }
    

    Sowas macht man halt nicht in "echten" PRogrammen, wo die Daten aus Dateien/Datenbanken/Internet/was weiß ich herkommen -- und nicht im Quellcode hardgecodet sind.

    Ich muss aber auch gestehen, dass ich dieses initializer_list-Zeug noich nicht 100% verstanden habe. Ich raffe nicht, wo die Elemente gespeichert werden, wie lange die leben. Die initializer_lists scheinen auch nicht gut mit "move semantic" kombinierbar zu sein. Die Iteratoren liefern nämlich immer Referenzen auf const. Und dann werden die temporären Strings wie string("Oskar") und so, wohl kopiert, statt "gemovet". ... (?)



  • otze schrieb:

    Aber was soll bitteschön das zweite sein? //edit: bedeutet das: der copy-ctor ist nicht vorhanden?

    Ja. Also wie wenn man heute etwas privat und undefiniert macht, aber mit leicht besserer Compilerfehlermeldung.

    otze schrieb:

    Und das Dritte?

    Neue enum s, die den umliegenden Scope nicht mehr überfluten. Mit class hat enum class rein gar nichts zu tun. enum struct wäre meiner Meinung nach um einiges besser gewesen, weil Struktur allgemeiner interpretierbar ist.

    otze schrieb:

    Ich glaube das Problem bei Typedef ist, dass Typedef einen Typen beschriebt. Ein Template-alias ist aber kein Typ. Es ist nur etwas, was irgendwann mal ein Typ werden könnte. Deswegen wäre Typedef inkonsistent.

    Danke, das scheint mir ein plausibler Grund zu sein. Dann kann ich die Entscheidung schon ein wenig besser nachvollziehen...



  • och schrieb:

    Mit Konsistenz meine ich, dass diese using-Syntax auch für "normale typedefs" herhalten kann.

    Ja, das hab ich schon so verstanden. Nur finde ich es etwas idealistisch, wenn davon ausgegangen wird, dass mehr syntaktische Möglichkeiten für ein und die selbe Semantik ausschliesslich zu einheitlicherem Code führen.

    Ich meine, bisher war doch alles recht verständlich. Initialisierungsbeispiel: Man nimmt Type obj(args) im allgemeinen Fall, Type obj = arg; für kompatible Typen, Type obj = {args} für Aggregate. Ich sehe keinen Anlass, diese Dinge gleich zu behandeln und dafür eine neue Schreibweise einzuführen. Noch dazu eine, die zwar viele Fälle vereinheitlicht, jedoch neue Inkonsistenzen mit sich bringt (siehe std::vector -Beispiel).

    och schrieb:

    Von dem initializer_list-Kram bin ich auch nicht gerade begeistert. Ich sehe da bis heute noch keine Verwendung für -- außer in kleinen (IMHO) praxisfernen Code-Beispielen wie

    Ich finde std::initializer_list ein sehr interessantes Feature, nur die Vermischung mit Konstruktoraufrufen bereitet mir etwas Sorgen. Beispielsweise existiert auch diese Form:

    return MyClass(47, "hallo"); // C++98
    
    return {47, "hallo"}; // C++0x
    

    Sicher keine schlechte Idee, gerade im Bezug auf Typinferenz mit auto und decltype . Aber warum die geschweiften Klammern? Ich hätte sowas schön gefunden:

    return auto(47, "hallo");
    

    Zurück zu std::initializer_list : Solche hardcodierten Listen sind zwar wie du sagst selten anzutreffen, aber vielleicht ergeben sich plötzlich neue Anwendungsfälle. Ein spontaner Einfall:

    // C++98
    CallbackSystem sys(47);
    sys.RegisterFunction(&Func1);
    sys.RegisterFunction(&Func2);
    sys.RegisterFunction(&Func3);
    
    // C++0x
    CallbackSystem sys(47, {&Func1, &Func2, &Func3})
    

    Initialisierungslisten können ja nicht nur als Datentabellen benutzt werden. Gibt es nicht auch eine Verwendung in Zusammenhang mit Variadic Templates? Ich kenne mich diesbezüglich auch zu wenig aus...



  • Hm, also zusammengefasst, hätte man auch typedef nehmen können, es wiederspricht aber etwas der logik, da nicht wirklich ein neuer Typ definiert wird.
    Andererseits schreibe ich bei Template-Klassen vor das class einfach template und störe mich nicht, dass eigentlich keine Klasse definiert wird.
    Über Sinn uns Unsinn, dafür (für Template-Aliases) ein neues syntaktsiches Konstrukt einzuführen, lässt sich also streiten.

    Gut, das eigentlich schon alles, was ich wissen wollte (wenn noch jemand einen guten Grudn für using hat, dann aber trotzdem immer her damit^^), ich danke allen für die Antworten.


Log in to reply