Beispiellösung

Content

Zur ersten Variante

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <limits>
#include <numeric>
#include <random>
#include <vector>

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;
   int last_selected_value = std::numeric_limits<int>::min();
   std::copy_if(values.begin(), values.end(),
      std::back_inserter(selected_values),
      [&](const int& value) -> bool {
	 if (value >= last_selected_value) {
	    last_selected_value = value;
	    return true;
	 } else {
	    return false;
	 }
      });

   /* 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;
}
theon$ g++ -Wall -o select-increasing2 select-increasing2.cpp
theon$ ./select-increasing2
   6  20  88  93  97  98  99 100
theon$ 

Zur zweiten Variante

Die zweite Variante scheitert zunächst daran, dass der Funktions-Operator implizit mit const deklariert wird. D.h. unser Lambda-Ausdruck entspricht folgendem Konstrukt:

class Anonymous {
   int counter = 1;
   void operator()(int& value) const {
      value = counter++;
   }
};

Das liefert einen ähnlichen Fehler:

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <vector>

class Anonymous {
   int counter = 1;
   void operator()(int& value) const {
      value = counter++;
   }
};

int main() {
   /* initialize values and fill it with values 1..100 */
   std::vector<int> values(100);
   std::for_each(values.begin(), values.end(), Anonymous());

   /* 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-numbers3 init-numbers3.cpp
init-numbers3.cpp: In member function 'void Anonymous::operator()(int&) const':
init-numbers3.cpp:9:22: error: increment of member 'Anonymous::counter' in read-only object
       value = counter++;
                      ^~
In file included from /opt/ulm/ballinrobe/include/c++/7.3.0/algorithm:62:0,
                 from init-numbers3.cpp:1:
/opt/ulm/ballinrobe/include/c++/7.3.0/bits/stl_algo.h: In instantiation of '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = __gnu_cxx::__normal_iterator >; _Funct = Anonymous]':
init-numbers3.cpp:16:59:   required from here
/opt/ulm/ballinrobe/include/c++/7.3.0/bits/stl_algo.h:3884:5: error: 'void Anonymous::operator()(int&) const' is private within this context
  __f(*__first);
  ~~~^~~~~~~~~~
init-numbers3.cpp:8:9: note: declared private here
    void operator()(int& value) const {
         ^~~~~~~~
theon$ 

Unter diesen Umständen darf counter nicht verändert werden.

Das mag vielleicht etwas überraschend sein, unterstreicht aber den Bezug zu funktionalen Programmiersprachen, bei denen so etwas auch nicht zulässig wäre. Es gibt die Möglichkeit, dies mit der Angabe des Schlüsselworts mutable zu umgehen. Dann ist es eine bewusste Entscheidung und das Schlüsselwort macht darauf aufmerksam, dass der Lambda-Ausdruck einen Status besitzt, den es selbst verändert:

#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) mutable { 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-numbers4 init-numbers4.cpp
theon$ ./init-numbers4
   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 100
theon$ 

Auf die gleiche Weise kann natürlich auch das andere Problem umgesetzt werden:

theon$ g++ -Wall -o select-increasing3 select-increasing3.cpp
theon$ ./select-increasing3
   6  20  88  93  97  98  99 100
theon$