Fehlerhaftes template



  • Hallo,

    Ich habe mir folgendes geschrieben um Pointer in Containern zu löschen. Bei meinen Borland-Compilern funktioiert das auch, aber nicht beim MinGW.
    Da kommt

    ..\..\Misc_Tools\lib_container_tools.h:30: error: variable or field delete\_ptr_container' declared void ..\\..\\Misc\_Tools\\lib\_container\_tools.h:30: error: template declaration ofint cont_lib::delete_ptr_container'
    ..\..\Misc_Tools\lib_container_tools.h:30: error: missing template arguments before '&' token
    ..\..\Misc_Tools\lib_container_tools.h:30: error: `cont' was not declared in this scope
    ..\..\Misc_Tools\lib_container_tools.h:30: error: expected primary-expression before "bool"
    ..\..\Misc_Tools\lib_container_tools.h:71: error: expected constructor, destructor, or type conversion before "getElemeByName"

    bei folgenden Code

    template< typename T, template<class> class C>
    void delete_ptr_container(C& cont, bool make_clear = true)
    {
    	std::for_each(cont.begin(), cont.end(), cont_lib::deleter<T*>());
    	if( make_clear ) cont.clear();
    }
    

    Was ist hier falsch?



  • Hallo,
    also erstmal fehlt C die Parameterliste. Du sagst dem Compiler nur, dass C ein Template mit *genau* einem Parameter ist, nicht aber mit was dieser ersetzt werden soll. Da müsste sowas wie C<T> oder C<T*> stehen.

    Und am Rande: dir ist klar, dass C so nicht durch einen Standard-Container ersetzt werden kann, oder?



  • Nein, das ist mir nicht klar. Warum nicht?
    Ich habe jetzt das <T> bei der Parameterliste eingefügt und es geht jetzt.


  • Mod

    Braunstein schrieb:

    Nein, das ist mir nicht klar. Warum nicht?

    Weil Standardcontainertemplates mindestens zwei Templateparameter (Elementtyp+Allokator, bei assoziativen und Hash-Containern kommt noch mehr hinzu) haben, die Implementation darf weitere Parameter hinzufügen, wenn diese geeignete Defaultargumente haben (das wird sich wohl in C++0x ändern). Ein Template mit zwei Parametern kann aber niemals Argument für einen Templatetemplateparameter, der ein Template mit einem Parameter erwartet, sein - selbst wenn der zweite Parameter ein Defaultargument hat (das ist ganz analog zum Verhältnis Funktionspointer vs. Funktionen mit Defaultargumenten).
    Besser handhaben lässt sich die Problematik, wenn der formale Parameter weniger speziell gewählt wird und wir statt dessen die möglichen Spezialisierungen per SFINAE einschränken. Also sinngemäß

    template<class C>
    typename boost::enable_if< is_container< C >/* ein geeignetes Prädikat, dass prüft, ob C ein Container ist */ >::type
    delete_ptr_container(C& cont, bool make_clear = true)
    {
        typedef typename C::value_type T;
        std::for_each(cont.begin(), cont.end(), cont_lib::deleter<T*>());
        if( make_clear ) cont.clear();
    }
    


  • Ok, den Allokator hatte ich total vergessen. Ich hatte diese Funktion bisher nur bei eigenen Container-Wrapper-Klassen verwendet, die keinen Allokator hatten. Da gab es natürlich keinen Fehler.
    Ich werde deine Variante mal ausprobieren.

    Danke euch beiden.



  • Wieso überhaupt mit SFINAE einschränken?
    Ich finde die Verwendung von SFINAE ehrlich gesagt reichlich pervers solange es nicht nötig ist, und in diesem Fall sehe ich keine Notwendigkeit.


  • Mod

    hustbaer schrieb:

    Wieso überhaupt mit SFINAE einschränken?
    Ich finde die Verwendung von SFINAE ehrlich gesagt reichlich pervers solange es nicht nötig ist, und in diesem Fall sehe ich keine Notwendigkeit.

    "reichlich pervers" halte ich für übertrieben, aber im Grundsatz hast du hier sicher recht: da delete_ptr_container hier "Container" schon im Namen enthält, ist eine sinnvolle Bedeutung für Nicht-Container undenkbar - mithin die Verwendung dieses Namens ohne einen Pointercontainer (oder Container aus Pointern?) per se ein Fehler: also sind Concept Checks angesagt:

    template<class C>
    void delete_ptr_container(C& cont, bool make_clear = true)
    {
        boost::function_requires< boost::ContainerConcept< C > >();
        typedef typename C::value_type T;
        BOOST_STATIC_ASSERT(( boost::is_pointer< T >::value ));
        std::for_each(cont.begin(), cont.end(), cont_lib::deleter<T>());
        if( make_clear ) cont.clear();
    }
    

Anmelden zum Antworten