UnaryFunction in c++ 17


  • Mod

    Also eine Art std::transform, aber als Bestandteil des Containers, so dass wegen Verzichts auf OutputIterator das Einfügen effizienter gestaltet werden kann, weil die Anzahl der Elemnte im voraus bestimmt werden kann? Und das ganze dann per Tagdispatching, um mit unterschiedlichen Iteratorkategorien effizient umzugehen?


  • Mod

    Dazu braucht es kein tag dispatching

    template <typename Iter, typename Container, typename UnaryF>
    void insert(Iter first, Iter last, Container& c, UnaryF f) {
      if constexpr (std::is_same_v<typename std::iterator_traits<Iter>::iterator_category,
                                   std::random_access_iterator_tag>)
        c.reserve(c.size() + std::distance(first, last));
    
      std::transform(first, last, f, std::back_inserter(c));
    }
    

    (Ungetestet)

    Edit: Warum kann man in diesem Textfeld nicht ordentlich per Hand einrücken?



  • Ok.

    Ich prüfe aktuell noch ob in der übergebenen Elementen begin bis end keine doppelten einträge vorhanden sind bevor ich die meinem eigentlichen Container hinzufüge:

    Iter temp(begin);
    for (; temp != end; ++temp)
    {
        auto var = func(*temp);
        const VarMap::iterator pos = _varMap.find(var->GetName());
        if (pos != _varMap.end())
        {
            map.clear();
            break;
        }
    
        Add(&map, var);
    }
    
    if (!map.empty())
    {
        _varMap.insert(map.begin(), map.end());
    }
    

    wie mache ich dass dann im Beispiel von Arcoth?



  • kommt drauf an was man unter tag dispatching versteht. 😉

    Aber könnte ich das nun nicht auch in einem enable_if direkt im template machen?


  • Mod

    booster schrieb:

    kommt drauf an was man unter tag dispatching versteht. 😉

    Ich verstehe darunter das dispatchen (Aufrufen) einer von mehreren Funktionen anhand von Tags.

    booster schrieb:

    Ich prüfe aktuell noch ob in der übergebenen Elementen begin bis end keine doppelten einträge vorhanden sind bevor ich die meinem eigentlichen Container hinzufüge:

    Das deutet auf einen Container hin, der prinzipiell keine doppelten Einträge haben darf. Warum also keine Hashmap/Hashset?



  • kommt drauf an was man unter tag dispatching versteht

    Das war eigentlich auf die Antwort von camper bezogen. Die er anscheinend wieder gelöscht hat. Die stand zuvor noch zwischen meinen beiden letzten Beiträgen.

    Warum also keine Hashmap/Hashset?

    also z.B. unordered_map?

    Wenn ich hier den back inserter verwende und alle elemente von begin und end reinpacke und hier wären doppelte Einträge vorhanden, würde eine Exception geworfen? Ist das richtig?



  • template <typename Iter, typename Container, typename UnaryF>
    void insert(Iter first, Iter last, Container& c, UnaryF f) {
      if constexpr (std::is_same_v<typename std::iterator_traits<Iter>::iterator_category,
                                   std::random_access_iterator_tag>)
        c.reserve(c.size() + std::distance(first, last));
    
      std::transform(first, last, f, std::back_inserter(c));
    }
    

    Darf ich zu dem Code nochmals Fragen stellen.
    1. Wo wird den hier nun geprüft ob der Inhalt des Inhals vom typ shared_ptr<MyVariable> ist?

    2. wieso wird im true fall im if constexpr nur das c.reserve. ausgeführt?
    Das hinzufügen passiert dann immer oder wie?



  • Hallo ich versuche mal meine Fragen selber zu beantworten

    1. Wo wird den hier nun geprüft ob der Inhalt des Inhals vom typ shared_ptr<MyVariable> ist?

    Gar nirgends. Da ging wohl die eigentliche Frage des Threads unter. 😞

    2. wieso wird im true fall im if constexpr nur das c.reserve. ausgeführt?

    Speicher nur reservieren wenn random access iterator !?

    Jetzt bleibt aber immer noch die Frage. Wie prüfe ich ob der Iterator auf elemente von shared_ptr<MyVariable> zeigt?



  • Warum also keine Hashmap/Hashset?

    nochmals dazu. Verwende aktuell eine std::map die hat ja auch unique key.

    Mein Vorhaben ist aber elemente die über first und last rein kommen zu überprüfen. Hier könnten ja doppelte Einträge vorhanden sein. Ich möchte alle elemente nur hinzufügen wenn kein doppelter eintrag vorhanden ist.

    würde ich nur

    std::transform(first, last, func, std::back_inserter(container));
    

    verwenden erhalte ich erst dann eine exception wenn ich einen doppelten Eintrage hinzufüge. Die bis dato eingefügten wären dann ja schon drin!


  • Mod

    booster schrieb:

    Warum also keine Hashmap/Hashset?

    nochmals dazu. Verwende aktuell eine std::map die hat ja auch unique key.

    ...

    würde ich nur

    std::transform(first, last, func, std::back_inserter(container));
    

    verwenden erhalte ich erst dann eine exception wenn ich einen doppelten Eintrage hinzufüge. Die bis dato eingefügten wären dann ja schon drin!

    Nope. Wenn dein container std::map ist, wird das gar nicht erst compilieren mangels push_back-Memberfunktion in std::map.

    Und wieso schon wieder std::map, wenn der Key doch schon Bestandteil des gemapten Types ist ? Für solche Fälle ist std::set da.

    Ich verstehe auch das Problem noch nicht. Wir haben hier keinen vollständigen minimalen Code und keine Fehlermeldung.


  • Mod

    booster schrieb:

    kommt drauf an was man unter tag dispatching versteht

    Das war eigentlich auf die Antwort von camper bezogen. Die er anscheinend wieder gelöscht hat. Die stand zuvor noch zwischen meinen beiden letzten Beiträgen.

    Die steht dort, wo sie immer stand.

    booster schrieb:

    Warum also keine Hashmap/Hashset?

    nochmals dazu. Verwende aktuell eine std::map die hat ja auch unique key.

    Bei näherer Betrachtung scheint ein set angebracht zu sein, da sich der Key innerhalb des Objekts befindet. Falls die Berechnung des Keys also nicht zu teuer ist, kannst du den key comparator entsprechend implementieren.

    booster schrieb:

    Die bis dato eingefügten wären dann ja schon drin!

    Natürlich. Ich dachte, es ginge darum, Duplikate zu entfernen, nicht, sie gar nicht erst als Input zuzulassen?

    Dass die eingefügten Elemente vom Typ Blabla sind... was macht das für einen Unterschied? Wenn das Einfügen kompiliert, sind sie kompatibel mit dem Elementtyp deines Containers.



  • @ camper.

    Nope. Wenn dein container std::map ist, wird das gar nicht erst compilieren mangels push_back-Memberfunktion in std::map.

    Ja das tut es nicht. Ich wollte ja auch gar keine allgemeine insert Funktion für irgendeinen beliebigen Container haben.

    Und wieso schon wieder std::map, wenn der Key doch schon Bestandteil des gemapten Types ist ? Für solche Fälle ist std::set da

    1. std::map wurde halt bisher im Code verwendet. Ich kann den Code nicht komplett auf einmal umstellen irgendwo muss ich anfangen.
    2. wenn ich nun set habe dann ist aber der gesamte typ der key wie suche ich dann nach einem element mit bestimmten Namen effizient.

    Ich verstehe auch das Problem noch nicht. Wir haben hier keinen vollständigen minimalen Code und keine Fehlermeldung.

    Nun ja weil ich noch nicht genau weiß wie implementieren
    Aber ich versuche mal ein Beispiel. Kommt...



  • @Arcoth

    Die steht dort, wo sie immer stand.

    Nein tut sie nicht! camper hat einen Eintrag erstellt der nun nicht mehr da ist.
    Egal tut nichts zur sache.

    Natürlich. Ich dachte, es ginge darum, Duplikate zu entfernen, nicht, sie gar nicht erst als Input zuzulassen?
    

    Echt wo habe ich das geschrieben? Eigentlich war die Anforderung nur Elemente hinzufügen wenn keine doppelten vorhanden sind.

    Aber ist hier auch nicht so wichtig. Lassen wir das auch erst mal ausser acht.

    Beispiel:
    Ich muss doch sagen dass ein Element vom typ blabla sein muss sonst erhalte ich keinen Kompilierungsfehler sondern einen Laufzeitfehler.


  • Mod

    Die find-Memberfunktion set von set hat einen Templateoverload, es ist also nicht zwingend erforderlich ein Containerelement zu erstellen, sofern der set-Kompartor das erlaubt. Das Beispiel hier macht es vor.


  • Mod

    booster schrieb:

    Die steht dort, wo sie immer stand.

    Nein tut sie nicht! camper hat einen Eintrag erstellt der nun nicht mehr da ist.
    Egal tut nichts zur sache.

    😮 camper, hast du etwa deine Moderatorenrechte dazu missbraucht, einen unsinnigen Beitrag zu vertuschen? So etwas machen wir doch nie! 🤡

    Echt wo habe ich das geschrieben?

    Exceptions? Also, das C++-Feature war gemeint, nahm ich an?


  • Mod

    Arcoth schrieb:

    booster schrieb:

    Die steht dort, wo sie immer stand.

    Nein tut sie nicht! camper hat einen Eintrag erstellt der nun nicht mehr da ist.
    Egal tut nichts zur sache.

    😮 camper, hast du etwa deine Moderatorenrechte dazu missbraucht, einen unsinnigen Beitrag zu vertuschen? So etwas machen wir doch nie! 🤡

    Ich gebrauche Löschrechte, falls ich schnell genug merke, Unsinn geschrieben zu haben, und noch keiner geantwortet hat. Und das ist schließlich immer noch da. K.A. was vermisst wird.

    Der Beitrag in diesem Thread, den ich gelöscht habe, war nur ein *facepalm* zu deiner Behauptung, tag-Dispatching wäre nicht erforderlich, nur im gleichzeitig im Beispiel die Codegenerierung anhand eines tags (per if constexpr) zu beeinflussen. Irgendwas Neues war da nicht drin.



  • @camper
    Ja ok das ist aber erst seit c++ 14 der Fall?
    Den Code den ich hier habe wurde vor 10 Jahren erstellt. Also wie gesagt ich versuche das alles umzusetzen und den Code zu optimieren. Aber zuerst muss ich das Projekt mal wieder zum laufen zu bringen.

    Also ich versuche es mal anders zu beschreiben:

    Möchte ich über die einzelnen Elemente iterieren die ich erhalte und dann auf ein Element zugreifen muss ich doch klar stellen dass ein Element vom typ MyVariable sein muss:

    class someclass
    {
        template <typename Iter>
        void do_something(Iter first, Iter last)
        {
            Iter temp(first);
            for(; temp != last; ++temp)
            {
                auto x = (*temp)->GetName();
                //...
            }
        }
    }
    

    Muss ich jetzt nicht so was machen:

    template <typename Iter, typename = std::enable_if<std::is_same_v<shared_ptr<MyVariable>, typename std::iterator_traits<Iter>::value_type >>>
    void do_something(Iter first, Iter last)
    


  • K.A. was vermisst wird.

    den ich gelöscht habe, war nur ein *facepalm* zu deiner Behauptung, tag-Dispatching wäre nicht erforderlich

    Ja den habe ich gemeint. Du hattest den Beitrag von Arcoth mit tag dsipatching zitiert und den *facepalm* drunter gesetzt. Den hatte ich gesehen. Und sofort darauf geantwortet. Also dann meine Antwort online war, war wiederum dein Eintrag weg. 😕


  • Mod

    booster schrieb:

    Möchte ich über die einzelnen Elemente iterieren die ich erhalte und dann auf ein Element zugreifen muss ich doch klar stellen dass ein Element vom typ MyVariable sein muss:

    class someclass
    {
        template <typename Iter>
        void do_something(Iter first, Iter last)
        {
            Iter temp(first);
            for(; temp != last; ++temp)
            {
                auto x = (*temp)->GetName();
                //...
            }
        }
    }
    

    Muss ich jetzt nicht so was machen:

    template <typename Iter, typename = std::enable_if<std::is_same_v<shared_ptr<MyVariable>, typename std::iterator_traits<Iter>::value_type >>>
    void do_something(Iter first, Iter last)
    

    C++ ist eine statisch typisiserte Sprache. Der einzige Unterschied zwischen der Variante mit enable_if gegenüber ohne ist die Art des Fehlers, die der Compiler liefert.
    Mit enable_if wird sich der Compiler beschweren, keine passende Überladung für den Funktionsaufruf gefunden zu haben, wenn der Iteratortyp nicht passt.
    Ohne enable_if wird während der Instantiierung der Funktion irgendetwas schiefgehen.

    enable_if dient primär dazu, zwischen mehreren andernfalls kollidierenden Überladungen auswählen zu können.
    Wenn sowieso klar ist, welche Überladung gemeint sein soll, wird enable_if eher verwirren. Wenn überhaupt käme ein static_assert innerhalb des Templates in Frage.
    z.B.

    template <typename InputIter, typename Func>
    void Add(InputIter begin, InputIter end, Func f)
    {
        static_assert(std::is_same_v<decltype(f(*begin)), decltype(_varMap)::mapped_type>);
        decltype(_varMap) tmp;
        for ( ; begin != end; )
        {
            auto var = f(*begin++);
            if (_varMap.find(var->GetName()) != _varMap.end())
                return;
            tmp.try_emplace(var->GetName(), var);
        }
        _varMap.merge(tmp);
    }
    

  • Mod

    booster schrieb:

    K.A. was vermisst wird.

    den ich gelöscht habe, war nur ein *facepalm* zu deiner Behauptung, tag-Dispatching wäre nicht erforderlich

    Ja den habe ich gemeint. Du hattest den Beitrag von Arcoth mit tag dsipatching zitiert und den *facepalm* drunter gesetzt. Den hatte ich gesehen. Und sofort darauf geantwortet. Also dann meine Antwort online war, war wiederum dein Eintrag weg. 😕

    data race 🙂 Vermutlich hast du innerhalb der 2-5 Sekunden zwischen meinem letztem Refresh und der Auslösung des Löschvorgangs gepostet.


Anmelden zum Antworten