...



  • haifaik schrieb:

    Unlogisch heisst hier "nicht mit dem Typsystem ausdruckbar". Deshalb ist ein const_cast angebracht.

    Oder wie wollt ihr das mit dem Typsystem ausdrücken ohne Hacks wie prev->next?



  • haifaik schrieb:

    haifaik schrieb:

    Unlogisch heisst hier "nicht mit dem Typsystem ausdruckbar". Deshalb ist ein const_cast angebracht.

    Oder wie wollt ihr das mit dem Typsystem ausdrücken ohne Hacks wie prev->next?

    Wo sich der Standard hier Gedanken gemacht hat war das Interface, nicht die Implementierung.



  • Du kannst es auch ohne const_cast implementieren. Nimm einen iterator und iteriere durch die Liste, bis const_iterator(iter) == pos :p



  • Kellerautomat schrieb:

    Du kannst es auch ohne const_cast implementieren. Nimm einen iterator und iteriere durch die Liste, bis const_iterator(iter) == pos :p

    Es müsste intern vielleicht einen Weg geben, einen const_iterator zu einem iterator umzuwandeln. Vielleicht einen privaten Konvertierungskonstruktor...



  • Noe, dann koennte man einen const_iterator ueber eine const list in einen iterator konvertieren. Der const_cast in erase ist schon korrekt so.



  • @K11t: Es spricht nichts gegen eine Konvertierungsfunktion.

    template <typename C>
    iterator to_iterator(C& c, typename C::const_iterator it) { return c.erase(it,it); }
    template <typename C>
    iterator to_iterator(C& c, typename C::iterator it)       { return it;             }
    

    Schöner wäre natürlich, wenn erase nicht so einen Sonderstatus hat und mit to_iterator implementiert wäre (das wiederum die Logik enthielte).


  • Mod

    http://ideone.com/Mrp6DC die gröbsten Fehler beseitigt, hoffe ich. sort und merge sind noch zu lang.



  • @camper:

    static_assert( std::is_same<T, typename std::allocator_traits<Allocator>::value_type>::value, "Allocator does not match value_type" );
    

    Warum?
    Ich habe mir bis erst einmal nen Allocator selbst geschrieben und habe ihn mit std::map verwendet - und da habe ich einfach einen alloc<bool> verwendet weil ich eh weiß dass er rebinded wird und alloc<std::pair<std::string, std::vector<datastd::string>>> irgendwie unnötig hässlich ist.

    Ist es hier sogar falsch? Immerhin verwendest du ja die allocator_traits um mit möglichen sehr exotischen Allokatoren kompatibel zu sein die reference nicht als T& bzw pointer nicht als T* deklarieren (oä.).
    Jedenfalls ist ein Pointer auf das data Element von node<T> immer T* - das T wird ja nicht vom Allokator alloziert sondern node<T>.


  • Mod

    Ethon schrieb:

    @camper:

    static_assert( std::is_same<T, typename std::allocator_traits<Allocator>::value_type>::value, "Allocator does not match value_type" );
    

    Warum?
    Ich habe mir bis erst einmal nen Allocator selbst geschrieben und habe ihn mit std::map verwendet - und da habe ich einfach einen alloc<bool> verwendet weil ich eh weiß dass er rebinded wird und alloc<std::pair<std::string, std::vector<datastd::string>>> irgendwie unnötig hässlich ist.

    Ist es hier sogar falsch? Immerhin verwendest du ja die allocator_traits um mit möglichen sehr exotischen Allokatoren kompatibel zu sein die reference nicht als T& bzw pointer nicht als T* deklarieren (oä.).
    Jedenfalls ist ein Pointer auf das data Element von node<T> immer T* - das T wird ja nicht vom Allokator alloziert sondern node<T>.

    Wenn ich mir 23.2.1/3 anschaue, muss value_type passen. Ausserdem muss ich das nochmal umschreiben

    n3337 schrieb:

    23.2.1/3
    For the components affected by this subclause that declare an allocator_type, objects stored in these
    components shall be constructed using the allocator_traits<allocator_type>::construct function and
    destroyed using the allocator_traits<allocator_type>::destroy function (20.6.8.2). These functions
    are called only for the container’s element type, not for internal types used by the container. [ Note: This
    means, for example, that a node-based container might need to construct nodes containing aligned buffers
    and call construct to place the element into the buffer. —end note]

    und es macht möglicherweise doch Sinn, ein Objekt beider Allokatortypen zu behalten, um nicht bei jeder Allokation eine Konvertierung vornehmen zu müssen.
    Allokation mit allocator_traits<node_allocator>::allocate
    Konstruktion mit allocator_traits<allocator_type>::construct für das Datenelement

    Mit einer C++03-map kannst du möglicherweise einen falschen Allokator als Templateargument verwenden, in C++11 sollte das ausgeschlossen sein.


  • Mod

    Ungefähr so müsste es korrekt sein.
    Wie ein Copy-/Move-Zuweisungsoperator auszusehen hat, der propagate_on_container_copy_assignment/propagate_on_container_move_assignment umsetzt, ist mir noch nicht klar.



  • std::addressof( node->data() )
    

    ➡

    std::allocator_traits<ConstructAllocator>::address( constr, node->data() )
    

    Edit: Oh! Die Memberfunktion address ist wohl ein Goodie von std::allocator .


Anmelden zum Antworten