Typ von Container-Element bestimmen.



  • Hallo zusammen,

    um die Kapazität eines Vectors auf die tatsächliche Elementanzahl zu trimmen gehe ich momentan folgendermassen vor (Anregung aus "Effective STL"):

    std::vector<int> v;
    v.reserve(100);
    v.push_back(4);
    //... etc. etc. -- verwendete Zahlen für reserver und push_back sind nur beispielhaft
    std::vector<int>(v).swap(v);
    // v ist nun getrimmt
    

    Also einfach ein temporäres Objekt erstellen und dann eben den Inhalt swappen.

    Falls ich allerdings den Typ der Container-Elemente nicht weiss, dacht ich mir könnte folgendes funktionieren:

    //... 
    decltype(v)(v).swap(v); // (1) funktioniert nicht
    std::vector<decltype(v[0])>(v).swap(v) // geht natürlich auch nicht, da decltype(v[0]) natürlich std::vector<int>::reference ist, welches ein typedef für int& ist
    

    Wie kann ich nun also an den Typ der Elemente gelangen? Ich könnte mir natürlich eine template-Funktion schreiben, allerdings muss das doch auch ohne zusätzliche Funktion funktionieren oder?

    Fehlermeldung bei (1):

    1>f:\win7-daten\visual studio 2010\projects\crap\crap\main.cpp(29): error C2143: Syntaxfehler: Es fehlt ';' vor '.'
    1>f:\win7-daten\visual studio 2010\projects\crap\crap\main.cpp(29): error C2086: 'std::vector<_Ty> v1': Neudefinition
    1>          with
    1>          [
    1>              _Ty=int
    1>          ]
    1>          f:\win7-daten\visual studio 2010\projects\crap\crap\main.cpp(21): Siehe Deklaration von 'v1'
    1>
    


  • Da das Kurzmachen eh eine eigene Bedeutung ist, kann man sie auch mit einem Namen versehen, und dann kriegt man den Typen geschenklt.

    temoplöate <typename V>
    void machKurz(V& v){
       v.swap(V());
    }
    


  • volkard schrieb:

    temoplöate

    Arbeitest du schon mit dem Übernächsten C++ Standard mit Unicode Support - C++50? 😃



  • Wenn du den Elementtyp des vector<>s wissen willst, wieso fragst du ihn dann nicht selber? (jeder Container bietet dafür ein typedef value_type ).

    PS: Wenn du nicht weißt, was für einen Typ du da hast, wie hast du den originalen Vector überhaupt erstellt?



  • CStoll schrieb:

    tpedef

    Haben wir den Mod-Rechtschreibefehler-Tag? 😃



  • EOutOfResources schrieb:

    CStoll schrieb:

    tpedef

    Haben wir den Mod-Rechtschreibefehler-Tag? 😃

    Nein, mein Schleppi kam nur nicht mit meiner Tippgeschwindigkeit mit 😃



  • Auf das typedef value_typ kann ich aber nur zugreifen, wenn ich die genaue Instanz des vector-templates kenne.
    Also beispielsweise

    std::vector<double>::value_type blub;
    

    Kenn ich diese nicht, komm ich da ja auch nicht ran - ausser eben wiederrum in einem Funktionstemplate.

    Grundsätzlich weiss ich natürlich, welchen Typ meine Vektoren haben - allerdings interessiert mich eben, ob es ausser durch eine weitere Templ.fkt. möglich ist für gegebene Containerobjekte (ohne den Template-Parameter bei der instanziierung der Klasse zu kennen) herrauszufinden, welchen Datentyp die Elemente haben.



  • Dich hindert nichts daran, V::value_type bzw typename V::value_type zu schreiben.



  • 314159265358979 schrieb:

    Dich hindert nichts daran, V::value_type bzw typename V::value_type zu schreiben.

    Hier ist das typename doch nicht notwendig, da es kein verdeckter anhängiger Name (Scottie) ist, oder?



  • Stimmt. Ich bin wohl schon etwas müde 🤡



  • Wie schon mehrfach erwähnt ist mir bewusst und klar, wie ich dies durch eine zusätzliches Funktions-Template bewerkstellige.

    Aber ich schrieb ja:

    ...allerdings interessiert mich eben, ob es ausser durch eine weitere Templ.fkt. möglich ist für gegebene Containerobjekte...

    Also nichts mit V::value_type



  • Also schön wird's fürchte ich nicht, und ich bin auch nicht sicher ob's wirklich standardkonform ist:

    #include <vector>
    #include <utility>
    
    int main()
    {
        std::vector<int> v;
    
        // 1
        typedef decltype(v) VT;
        VT(v).swap(v);
    
        // 2
        typename std::identity<decltype(v)>::type(v).swap(v);
    
        // 3 (sinnlos, da noch viel umständlicher als (2))
        std::vector<typename std::identity<decltype(v)>::type::value_type>(v).swap(v);
    }
    


  • Ich steig hier gerade total aus. Wo liegt das Problem? Was habt ihr vor? Ich kapier den Aufwand nicht.



  • @314159265358979

    Auftrag:

    #include <vector>
    // weitere includes die du brauchst
    
    int main()
    {
        std::vector<int> v;
    
        // Schreibe hier code hin, der ein neues Objekt vom Typ von "v" erzeugt,
        // mit dem Inhalt von "v" initialisiert, und ruft dann "neuesObjekt.swap(v)" auf.
        // Und zwar ohne Hilfsfunktionen bzw. Templates, und ohne dass der Typ des Vektors (hier int) eine Rolle spielt.
    }
    


  • #include <vector>
    #include <algorithm>
    
    int main()
    {
        std::vector<int> v;
    
        int size = sizeof(v.front());
    
        std::vector<char> v2(reinterpret_cast<char*>(&v.front()), reinterpret_cast<char*>(&v.back()) + size);
        v.clear();
        v.resize(v2.size() / size);
    
        std::copy(v2.begin(), v2.end(), reinterpret_cast<char*>(&v.front()));
    }
    

    Aus dem Kopf heraus, ungetestet :p

    Edit: Ganz vergessen, dass clear() ja keinen Speicher frei gibt. Dann weiß ich's auch nicht, ohne decltype zu verwenden. (Edit2: Bzw ohne mich auf Internas der Implementierung zu verlassen.)

    Edit #3:
    Hier nochmal eine Möglichkeit. Standardkonform ist's nicht, aber sollte eigentlich bei allen Implementierungen zumindest im Release-Mode hinhauen.

    #include <vector>
    
    int main()
    {
        std::vector<int> v;
    
        assert(sizeof(v) == sizeof(std::vector<char>));
        std::vector<char>(reinterpret_cast<char*>(&v.front()), reinterpret_cast<char*>(&v.back()) + sizeof(v.front()).swap(reinterpret_cast<std::vector<char>&>(v));
    }
    


  • @314159265358979:
    OMFG. Das ist einer der dümmsten Scherze die du seit langem gemacht hast.

    Und "es sollte" auch nicht "eigentlich hinhauen".



  • hustbaer schrieb:

    @314159265358979:
    OMFG.

    Gerade als ich auf "Zitieren" klicken wollte, hast du editiert. Ich dachte, wir hätten einen std::vector<int>, nur dürfen wir nirgens int hinschreiben. Das ist natürlich was anderes.



  • hustbaer schrieb:

    // Und zwar ohne Hilfsfunktionen bzw. Templates, und ohne dass der Typ des Vektors (hier int) eine Rolle spielt.
    

    Ich hatte angenommen dass das klar genug ist. War es anscheinend nicht. Aber gut, jetzt weisst du was gemeint ist 🙂



  • Beim zweiten mal lesen völlig klar. assert(PI.brain_state() != brain_state.TIRED); kabumm.



  • @PI
    Dass deine Lösung ein Satz mit x war, ist dir vermutlich selber klar 🙂

    @hustbaer
    Ich danke dir für die Lösungsvorschläge.
    Auf Lösung 1 hätte ich natürlich auch schnell selber kommen können, allerdings ist mir völlig unklar warum

    typedef decltype(v) VT;
    VT(v).swap(v);
    

    funktioniert,

    der compiler bei

    decltype(v)(v).swap(v)
    

    rummeckert. Wird vermutlich damit zu tun haben, wie Ausdrücke geparst werden.

    Lösung 3 hat keinen Vorteil gegenüber Lösung 2, und an std::identity hab ich überhaupt garnicht mehr gedacht. Danke für den Tip.

    Inwiefern hast du bedenken, dass Lösung 2 nicht standardkonform ist?

    Besten Dank nochmals für eure Vorschläge.


Log in to reply