std::accumulate: Merkwürdiger Fehler bei vector<vector>
-
Wenn man will kann man sich auch einen Wrapper schreiben ders richtig macht:
#include <iostream> #include <numeric> #include <vector> template <typename InputIt> auto sum(InputIt first, InputIt last, typename std::remove_reference<decltype(*first)>::type init) -> decltype(init) { return std::accumulate(first, last, init); } int main() { std::vector<double> v = { 0.5, 1, 2 }; std::cout << sum(v.begin(), v.end(), 0 /*Jetzt auch ohne Dezimal-Punkt!*/) << '\n'; }Eigentlich nervig dass sowas nicht der Standard ist... warum eigentlich nicht? Hab als ich den Fehler das erste mal hatte auch ewig gebraucht bis ich das gemerkt habe

-
Weil
accumulateallgemein genug sein soll, auch auf Typen addieren zu können, die mit dem Containerelement nichts am Hut haben.PS: Du suchst womöglich
iterator_traits<>::value_type.
-
Arcoth schrieb:
Weil
accumulateallgemein genug sein soll, auch auf Typen addieren zu können, die mit dem Containerelement nichts am Hut haben.Sorry, aber das versteh ich nicht?
-
happystudent schrieb:
Arcoth schrieb:
Weil
accumulateallgemein genug sein soll, auch auf Typen addieren zu können, die mit dem Containerelement nichts am Hut haben.Sorry, aber das versteh ich nicht?
Sagen wir mal, du hast einen Typen, der nicht zu
intkonvertierbar ist. Auf den ich aberintaddieren kann. I.e.+= iist möglich. Dann wird das von der STL vorgegebeneaccumulateproblemlos funktionieren, deines aber nicht.
-
Arcoth schrieb:
Sagen wir mal, du hast einen Typen, der nicht zu
intkonvertierbar ist. Auf den ich aberintaddieren kann. I.e.+= iist möglich. Dann wird das von der STL vorgegebeneaccumulateproblemlos funktionieren, deines aber nicht.Ok, da hast du recht, das hatte ich nicht bedacht... naja, vielleicht geht das ja dann mit concepts-Überladungen sauber (da kenn ich mich aber noch nicht wirklich aus). Weil ungünstig finde ich das trotzdem^^
-
Nur als Nachtrag: Mit dem double (0.0) war das Problem dann auch gelöst, danke
-
Arcoth schrieb:
Sagen wir mal, du hast einen Typen, der nicht zu
intkonvertierbar ist. Auf den ich aberintaddieren kann. I.e.+= iist möglich. Dann wird das von der STL vorgegebeneaccumulateproblemlos funktionieren, deines aber nicht.Ich hab nochmal ein bisschen darüber nachgedacht und so ganz passt mir diese Erklärung nicht (vielleicht verstehe ich auch was falsch).
Laut Doku sieht der Code von
std::accumulateetwa so aus (entspricht auch dem meines Compilers VS2013):template<class InputIt, class T> T accumulate(InputIt first, InputIt last, T init) { for (; first != last; ++first) { init = init + *first; } return init; }Den Wertetyp des Input-Iterators nenne ich mal
T.Du meinst also man kann auf ein
Teinenintaddieren. Allerdings istTja auf der rechten Seite, also müsste man wenn dann denoperator+mitintals linksseitigem Argument undTals rechtsseitigem Argument überladen. Außerdem muss dieseroperator+dann etwas zuintkonvertierbares zurückgeben, dainit(vom Typint) gleich diesem gesetzt wird. Daher kann man schonmal nicht einintauf einTaddieren, sondern höchstens einTauf einintaddieren. Und das Ergebnis muss dann wieder einint(bzw. in ein solches konvertierbar) sein.Das heißt, die einzige Möglichkeit die mir einfällt dein Szenario umzusetzen wäre so:
struct foo { int val = 0; }; // Nicht zu int konvertierbar ... int operator+(int i, foo const &f) { return i + f.val; } // ... aber auf int addierbarDas scheint aber keinen Sinn zu machen. Denn dann gilt folgendes:
foo f; int i = f; // Geht nicht int j = 0 + f; // Gehtwas offensichtlich semantisch gesehen Mist ist.
-
@happystudent Ne, ich meinte folgendes:
struct A { A operator+(int); }; int arr[] {1, 2, 3}; std::accumulate(arr, arr+3, A());
-
Das hier wäre sogar ein halbwegs sinnvoller Anwendungsfall:
vector<char> foo = {'T', 'e', 's', 't'}; auto str = accumulate(foo.begin(), foo.end(), string());
-
Stimmt, ihr habt recht. Daran hatte ich nicht gedacht
