Lambda-Ausdrücke mit einer Capture
Content |
Wenn wir Lambda-Ausdrücke mit einem internen Status wie beim Prädikat IsIncreasing wünschen, muss die entsprechende Variable in die capture aufgenommen werden.
Wie lässt sich nun die Verwendung von IsIncreasing durch einen Lambda-Ausdruck ersetzen? Dazu gibt es zwei Ansätze:
-
Wir deklarieren eine entsprechende lokale Variable außerhalb des Lambda-Ausdrucks in dem umgebenden Block und übernehmen diese per Referenz.
-
Beginnend mit C++14 ist es möglich, in der capture eine Initialisierung zu verwenden.
Beide Techniken können wir zunächst einsetzen, um das Array mit den Werten 1 bis 100 zu initialisieren.
Hier ist die erste Variante:
#include <algorithm> #include <iomanip> #include <iostream> #include <vector> int main() { /* initialize values and fill it with values 1..100 */ std::vector<int> values(100); int counter; std::for_each(values.begin(), values.end(), [&](int& value) { value = counter++; }); /* print values */ int count = 0; for (auto value: values) { std::cout << std::setw(4) << value; if (++count % 10 == 0) std::cout << std::endl; } std::cout << std::endl; }
theon$ g++ -Wall -o init-numbers init-numbers.cpp theon$ ./init-numbers 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 theon$
So könnte im ersten Ansatz die zweite Variante aussehen:
#include <algorithm> #include <iomanip> #include <iostream> #include <vector> int main() { /* initialize values and fill it with values 1..100 */ std::vector<int> values(100); std::for_each(values.begin(), values.end(), [counter = 1](int& value) { value = counter++; }); /* print values */ int count = 0; for (auto value: values) { std::cout << std::setw(4) << value; if (++count % 10 == 0) std::cout << std::endl; } std::cout << std::endl; }
theon$ g++ -Wall -o init-numbers2 init-numbers2.cpp init-numbers2.cpp: In lambda function: init-numbers2.cpp:10:50: error: increment of read-only variable 'counter' [counter = 1](int& value) { value = counter++; }); ^~ theon$
Frage und Aufgabe
-
Ersetzen Sie IsIncreasing durch einen Lambda-Ausdruck entsprechend der ersten Variante.
-
Weswegen scheitert die zweite Variante?
Vorlage
#include <algorithm> #include <iomanip> #include <iostream> #include <limits> #include <numeric> #include <random> #include <vector> struct IsIncreasing { bool operator()(const int& value) { if (value >= last_selected_value) { last_selected_value = value; return true; } else { return false; } } int last_selected_value = std::numeric_limits<int>::min(); }; int main() { /* initialize values and fill it with shuffled values 1..100 */ std::vector<int> values(100); std::iota(values.begin(), values.end(), 1); std::shuffle(values.begin(), values.end(), std::mt19937(2)); /* select all even values out of it */ std::vector<int> selected_values; std::copy_if(values.begin(), values.end(), std::back_inserter(selected_values), IsIncreasing()); /* print selected values */ int count = 0; for (auto value: selected_values) { std::cout << std::setw(4) << value; if (++count % 10 == 0) std::cout << std::endl; } std::cout << std::endl; }