Please disable Adblockers and enable JavaScript for domain CEWebS.cs.univie.ac.at! We have NO ADS, but they may interfere with some of our course material.

Die Aufgabe besteht darin, nach der Hälfte der Elemente (current_size/2) alle Elemente bis zum letzten Element (also current_size-current_size/2-1 Elemente) zu überspringen. 
 
Bei den folgenden Lösungsvarianten werden im Iterator zusätzlich die aktuelle Position des Iterators (size_t n), die Anzahl der Elemente im ADS_set (size_t current_size) und der Modus (bool special) gespeichert. Die bool-Variable für den Modus wird eigentlich nicht benötigt, da der Modus spezial bereits eindeutig daran erkennbar ist, dass die neue Iterator-Instanzvariable current_size != 0 ist. Sie wird hier nur zwecks plakativer Verdeutlichung der Vorgangsweise verwendet. 
 
Will man ohne special auskommen, läßt man die Instanzvariable special und den Parameter special weg und ersetzt im Code des operator++ überall special durch current_size
 
Wenn hingegen bereits der originale Iterator die Anzahl der Elemente speichert, benötigt man zusätzlich nur special und kann auf die zusätzliche (und dann redundante) Instanzvariable current_size verzichten. Im Code des operator++ wird dann überall current_size durch die bereits vorhandene Instanzvariable ersetzt. 

Zusätzliche Instanzvariablen im Iterator

bool special {false};
size_t current_size{0};
size_t n {0};

Iterator-Konstruktor

Es wird ein bestehender Konstruktor um zwei Parameter und entsprechende Initialisierungen erweitert. 
 
explicit Iterator(/*constructor parameters*/, bool special = false, size_t current_size = 0): /*other initializations*/, special{special}, current_size{current_size} { /*constructor code*/ }

z()

z() wird von begin() abgeleitet: 
 
const_iterator begin() const { return const_iterator{/*constructor parameters*/}; }
 
const_iterator z() const { return const_iterator{/*constructor parameters*/, true, current_size}; }

operator++() Spezialfall (häufig)

Wenn der operator++ nur ein einziges return aufweist und sich diese am Ende der Funktion befindet, also der operator++ so aussieht: 
 
Iterator &operator++() {
  // operator++ code - no returns
  return *this;
}
 
dann kann die Aufgabe zB so implementiert werden: 
 
Iterator &operator++() {
  if (special && ++n == current_size/2) {
    for (size_t i{0}; i < current_size-current_size/2-1; ++i) {
      // operator++ code - no returns
    }
  }
  // operator++ code - no returns
  return *this;
}
 
Der ursprüngliche operator++ code wird hier dupliziert, das wird von manchen als unelegant empfunden und kann bei längerem Code auch recht unübersichtlich werden. Eine Alternative ohne Code-Duplizierung: 
 
Iterator &operator++() {
  do {
    // operator++ code - no returns
  } while (special && ++n >= current_size/2 && n < current_size-1);
  return *this;
}
 
Diese Variante entspricht abgesehen von der anderen Zählweise der hier beschriebenen Variante
 
Auch alle im folgenden beschriebenen Varianten für den allgemeinen Fall eignen sich für den Spezialfall mit einem einzigen return am Ende.  

operator++() Allgemeiner Fall

Die folgenden Varianten funktionieren unabhängig von der Zahl der return-Anweisungen im operator++ code (und damit auch für den Spezialfall mit einem einzigen return am Ende). Der ursprüngliche operator++() sieht so aus: 
 
Iterator &operator++() {
  // operator++ code
}
 
Der operator++() ruft sich zum Weiterschalten in einer entsprechend oft durchgeführten Schleife selbst (also rekursiv) auf. Der rekursive Aufruf erfolgt durch ++*this oder alternativ durch operator++() bzw. this→operator++()
 
Iterator &operator++() {
  if (special && ++n == current_size/2) {
    for (size_t i{0}; i < current_size-current_size/2-1; ++i) {
      ++*this;
    }
  }
  // operator++ code
}
 
Natürlich kann man auch die Schleife selbst durch eine Rekursion ersetzen (mit den üblichen Nebenwirkungen): 
 
Iterator &operator++() {
  if (special && ++n >= current_size/2 && n < current_size-1) ++*this;
  // operator++ code
}
 
Will man ohne Rekursion auskommen, dann kann auch der gesamte operator++ code in eine neue private Funktion (inc) ausgelagert werden. inc() ist also eine private Kopie von operator++() mit anderem Namen. 
 
Iterator &inc() {
  // operator++ code
}
 
In allen obigen Varianten für den Spezialfall kann dann 
// operator++ code - no returns
durch 
inc();
ersetzt werden, um diese auch für den allgemeinen Fall tauglich zu machen. 
 
Also 
Iterator &operator++() {
  if (special && ++n == current_size/2) {
    for (size_t i{0}; i < current_size-current_size/2-1; ++i) {
      inc();
    }
  }
  inc();
  return *this;
}
bzw. kürzer 
Iterator &operator++() {
  if (special && ++n == current_size/2) {
    for (size_t i{0}; i < current_size-current_size/2-1; ++i) {
      inc();
    }
  }
  return inc();
}
und 
Iterator &operator++() {
  do {
    inc();
  } while (special && ++n >= current_size/2 && n < current_size-1);
  return *this;
}
 
 
Wie immer wird davon ausgegangen, dass der Postfix-Operator den Präfix-Operator verwendet und daher nicht geändert zu werden braucht. 
Letzte Änderung: 10.12.2022, 11:28 | 522 Worte