Funktionsobjekte

Content

Funktionsobjekte sind alle Objekte, die wie eine Funktion benutzt werden können. Dies schließt

Mit Funktionsobjekten werden zahlreiche Algorithmen parametrisiert. Im folgenden Beispiel wird std::copy_if aus #include <algorithm> genutzt, um mit Hilfe eines Prädikats bei einer mit Iteratoren spezifizierten Menge von Objekten eine Auswahl zu treffen:

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

bool is_even(const int& value) {
   return value % 2 == 0;
}

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), is_even);

   /* 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;
   }
}

Ein paar Erläuterungen zu dem Beispiel:

So sieht die Ausführung aus:

theon$ g++ -Wall -o select-even select-even.cpp
theon$ ./select-even
   6  20  18  88  48  70  90  54  56  64
  42  76  52  96  60  58  34   2  98  66
  46   8  10  26  14  86   4  32  92  84
  62  50  36  74  16  38  72  30  24  82
  68  22  28  78  94  44 100  12  80  40
theon$ 

Natürlich kann die Funktion auch durch eine Klasse mit einem passenden Funktionsoperator ersetzt werden:

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

struct IsEven {
   bool operator()(const int& value) {
      return value % 2 == 0;
   }
};

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), IsEven());

   /* 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;
   }
}
theon$ diff -U 2 select-even.cpp select-even2.cpp
--- select-even.cpp	Thu Jun 21 10:58:03 2018
+++ select-even2.cpp	Thu Jun 21 10:57:47 2018
@@ -6,7 +6,9 @@
 #include 
 
-bool is_even(const int& value) {
-   return value % 2 == 0;
-}
+struct IsEven {
+   bool operator()(const int& value) {
+      return value % 2 == 0;
+   }
+};
 
 int main() {
@@ -19,5 +21,5 @@
    std::vector selected_values;
    std::copy_if(values.begin(), values.end(),
-      std::back_inserter(selected_values), is_even);
+      std::back_inserter(selected_values), IsEven());
 
    /* print selected values */
theon$ g++ -Wall -o select-even2 select-even2.cpp
theon$ ./select-even2
   6  20  18  88  48  70  90  54  56  64
  42  76  52  96  60  58  34   2  98  66
  46   8  10  26  14  86   4  32  92  84
  62  50  36  74  16  38  72  30  24  82
  68  22  28  78  94  44 100  12  80  40
theon$ 

Das bringt hier zunächst nur etwas mehr Text. Aber auf Klassen basierende Funktionsobjekte haben einen Vorteil: Sie können einen Status verwalten und diesen in die Entscheidung einfließen lassen.

Aufgabe

Ersetzen Sie die Prädikatsklasse IsEven durch ein Prädikat Increasing, das das erste Element immer akzeptiert und die weiteren nur dann, wenn sie monoton steigend sind.

Vorlage

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

struct IsEven {
   bool operator()(const int& value) {
      return value % 2 == 0;
   }
};

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), IsEven());

   /* 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;
   }
}