Wozu braucht std::accumulate einen operator< ?



  • Compiler nennen



  • Sieht nach dem MSVC aus...



  • volkard schrieb:

    lauffähiges programm schicken.

    Bitteschön:

    #include <numeric>
    #include <vector>
    
    struct container
    {
    	using iter = std::vector<int>::iterator;
    
    	struct iterator : std::iterator<std::random_access_iterator_tag, int>
    	{
    		iterator(iter it_) : it(it_) {}
    		bool operator==(iterator const &other_) { return it == other_.it; }
    		bool operator!=(iterator const &other_) { return !(*this == other_); }
    
    		iterator &operator++() { ++it; return *this; }
    		iterator operator++(int) { const iterator old(*this); ++(*this); return old; }
    		iterator &operator--() { --it; return *this; }
    		iterator operator--(int) { const iterator old(*this); --(*this); return old; }
    
    		int &operator*() { return *it; }
    		int *operator->() { return &(*it); }
    		iter it;
    	};
    
    	iterator begin() { return iterator(data.begin()); }
    	iterator end() { return iterator(data.end()); }
    
    	std::vector<int> data;
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	container c;
    	c.data = { 1, 2, 3, 4, 5 };
    	std::cout << std::accumulate(c.begin(), c.end(), 0);
    }
    

    manni66 schrieb:

    Compiler nennen

    Visual Studio Professional 2013.



  • happystudent schrieb:

    int _tmain(int argc, _TCHAR* argv[])
    

    ist fehlerhaft. kann nicht weitertesten.

    menno, du bist doch schon lange genug im forum, wenigstens den antwortern ein mindestmaß an höflichgkeit entgegenbringen und testbaren code zeigen. also nur du machst die anpassungen und nicht 100 hilfbereite leser.


  • Mod

    Dein Iterator erfüllt die Anforderungen an einen random access Iterator nicht, obwohl du angibst, dass er das täte. Das darf dann auch gerne mal nicht compilieren. Vermutlich benutzt die Implementierung hier nämlich eine Templatespezialisierung, bei der irgendeine tolle Optimierung für random access Iterator gemacht wird, die operator< benutzt (den ein random access Iterator haben muss). Das ist sehr löblich von der Implementierung, genau diese Art von Optimierungen erwarte ich, dazu sind die Iteratortags da. Dass es funktioniert, wenn du einen Dummy-Operator implementierst ist reiner Zufall und wird sicherlich in anderen Testfällen fehlschlegen. Du musst den Operator schon noch richtig implementieren (Totalordnung) und auch die anderen Anforderungen an einen random access Iterator erfüllen oder eben das Tag droppen. Dein Iterator ist derzeit ein output_iterator.

    volkard schrieb:

    menno, du bist doch schon lange genug im forum, wenigstens den antwortern ein mindestmaß an höflichgkeit entgegenbringen und testbaren code zeigen. also nur du machst die anpassungen und nicht 100 hilfbereite leser.

    +1



  • SeppJ schrieb:

    Vermutlich benutzt die Implementierung hier nämlich eine Templatespezialisierung, bei der irgendeine Art von Optimierung für random access Iterator gemacht wird, die operator< benutzt (den ein random access Iterator haben muss).

    Oder vielleicht diese komische Deoptimierung von MS, die C++ lahmer als C# macht. Geprüfte Iteratoren, dafür böte sich ein op< direkt an.


  • Mod

    volkard schrieb:

    SeppJ schrieb:

    Vermutlich benutzt die Implementierung hier nämlich eine Templatespezialisierung, bei der irgendeine Art von Optimierung für random access Iterator gemacht wird, die operator< benutzt (den ein random access Iterator haben muss).

    Oder vielleicht diese komische Deoptimierung von MS, die C++ lahmer als C# macht. Geprüfte Iteratoren, dafür böte sich ein op< direkt an.

    Ist es unvorstellbar, dass das eine Optimierung ist? Warum konkret der op< benötigt wird, weiß ich zwar nicht (vielleicht wirklich was, dass die Funktion abbricht, wenn begin > end), aber es ist ja schon gut vorstellbar, dass der Code von accumulate für array-artige Objekte optimiert werden kann.



  • volkard schrieb:

    ist fehlerhaft. kann nicht weitertesten.

    menno, du bist doch schon lange genug im forum, wenigstens den antwortern ein mindestmaß an höflichgkeit entgegenbringen und testbaren code zeigen. also nur du machst die anpassungen und nicht 100 hilfbereite leser.

    Kann dir nicht ganz folgen. Der Code ist natürlich fehlerhaft, da er ja das Problem zeigen soll dass das accumulate nicht compiliert. Wenn man aber den Aufruf durch das im ersten Post gezeigt accumulate ersetzt läuft es auch. Hab den Code schließlich extra getestet bevor ich ihn hier gepostet habe.

    Versteh nicht was das mit Höflichkeit zu tun hat, hab mir durchaus Mühe beim formulieren der Frage etc gegeben.

    SeppJ schrieb:

    Dein Iterator erfüllt die Anforderungen an einen random access Iterator nicht, obwohl du angibst, dass er das täte. Das darf dann auch gerne mal nicht compilieren. Vermutlich benutzt die Implementierung hier nämlich eine Templatespezialisierung, bei der irgendeine Art von Optimierung für random access Iterator gemacht wird, die operator< benutzt (den ein random access Iterator haben muss).

    Also heißt das dass ich mich nicht darauf verlassen kann wenn in der Doku steht die Funktionen seien in ihrer Funktionsweise äquivalent? Ich dachte wenn das da steht gilt das auch für alle Fälle?


  • Mod

    happystudent schrieb:

    Kann dir nicht ganz folgen. Der Code ist natürlich fehlerhaft, da er ja das Problem zeigen soll dass das accumulate nicht compiliert. Wenn man aber den Aufruf durch das im ersten Post gezeigt accumulate ersetzt läuft es auch. Hab den Code schließlich extra getestet bevor ich ihn hier gepostet habe.

    volkard hat doch extra die zu beanstandende Stelle zitiert. Dein Code ist kein Standard-C++. Ich musste erst eine passende Signatur für main selber schreiben. Es hat auch prompt überraschend viel Arbeit gekostet (für mich), da ich mich vertippt habe. Außerdem haben die Header iostream und iterator gefehlt.

    Also heißt das dass ich mich nicht darauf verlassen kann wenn in der Doku steht die Funktionen seien in ihrer Funktionsweise äquivalent? Ich dachte wenn das da steht gilt das auch für alle Fälle?

    Doch kannst du. Du schreibst es doch selber: äquivalent. Ist er ganz bestimmt auch. Außerdem hat die Funktion die Anforderung, dass die Iteratoren mindestens Input Iteratoren sind (sind deine auch). Du hast hier aber den Compiler angelogen, als du deinem Iterator das random_access_iterator-Flag verpasst hast. Denn dein Iterator erfüllt nicht die Anforderungen daran. Das accumulate darf natürlich auch mehr nutzen als die Mindestanforderungen, wenn dies erfüllt ist*. Wenn du nun sagst, dass dein Iterator mehr kann, dann merkt das accumulate das und wählt eine entsprechend raffiniertere Implementierung, die dies ausnutzt. Wenn dein Iterator dann aber deine Versprechen nicht halten kann, kommt es zum beobachteten Fehler.
    Wenn du bloß das output_iterator-Flag setzen würdest (das ist das höchste, was dein Iterator derzeit unterstützt); oder gar kein Flag setzt (dann wird eben angenommen, dass die dokumentierte Mindestanforderung - Input Iterator - erfüllt ist); oder einen richtigen random access Iterator implementiertst, dann wird es auch funktionieren.
    C++-Standard über den Sinn von Iterator-Tags:

    24.4.3,1 schrieb:

    It is often desirable for a function template specialization to find out what is the most specific cate-
    gory of its iterator argument, so that the function can select the most efficient algorithm at compile
    time. To facilitate this, the library introduces category tag classes which are used as compile time tags
    for algorithm selection. They are: input_iterator_tag, output_iterator_tag, forward_iterator_tag,
    bidirectional_iterator_tag and random_access_iterator_tag. For every iterator of type Iterator,
    iterator_traits<Iterator>::iterator_category shall be defined to be the most specific category tag
    that describes the iterator’s behavior.

    Wenn du die Tags benutzt, dann musst du auch wissen, wozu sie überhaupt da sind.

    *: Und das ist auch gut so! Das ist das Geheimnis hinter vielen der Optimierungen von algorithms. Die Referenzimplementierungen zu denen die Algorithmen äquivalent sein sollen sind sehr allgemein und daher oft suboptimal. Erst durch die Templatemagie kann automatisch die beste Version gewählt werden.



  • SeppJ schrieb:

    volkard hat doch extra die zu beanstandende Stelle zitiert. Dein Code ist kein Standard-C++. Ich musste erst eine passende Signatur für main selber schreiben. Es hat auch prompt überraschend viel Arbeit gekostet (für mich), da ich mich vertippt habe. Außerdem haben die Header iostream und iterator gefehlt.

    Ach so, es ging um die main-Signatur. Ok, das hab ich vergessen, sorry dafür. Ist aber auch ziemlich nervig dass schon die Main (und damit ja eigentlich jedes Programm) von VS per default nicht Standard Konform ist...

    SeppJ schrieb:

    Doch kannst du. Du schreibst es doch selber: äquivalent. Ist er ganz bestimmt auch. Außerdem hat die Funktion die Anforderung, dass die Iteratoren mindestens Input Iteratoren sind (sind deine auch). Du hast hier aber den Compiler angelogen, als du deinem Iterator das random_access_iterator-Flag verpasst hast. Denn dein Iterator erfüllt nicht die Anforderungen daran. Das accumulate darf natürlich auch mehr nutzen als die Mindestanforderungen, wenn dies erfüllt ist*. Wenn du nun sagst, dass dein Iterator mehr kann, dann merkt das accumulate das und wählt eine entsprechend raffiniertere Implementierung, die dies ausnutzt. Wenn dein Iterator dann aber deine Versprechen nicht halten kann, kommt es zum beobachteten Fehler.
    Wenn du bloß das output_iterator-Flag setzen würdest (das ist das höchste, was dein Iterator derzeit unterstützt); oder gar kein Flag setzt (dann wird eben angenommen, dass die dokumentierte Mindestanforderung - Input Iterator - erfüllt ist); oder einen richtigen random access Iterator implementiertst, dann wird es auch funktionieren.

    Ok alles klar. Ich hatte mich gewundert warum accumulate diesen Operator braucht, wenn da natürlich irgendeine template-Optimierungs-Magie dahinter steckt wird es wohl schon einen Sinn machen.

    Danke für die Hilfe 👍



  • happystudent schrieb:

    Ist aber auch ziemlich nervig dass schon die Main (und damit ja eigentlich jedes Programm) von VS per default nicht Standard Konform ist...

    Man lässt sich main() auch nicht von der IDE generieren...


Anmelden zum Antworten