C++-Iterator-Unterstützung für Delphi-Aufzählungstypen und -Container

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Sprachunterstützung für die RAD Studio-Bibliotheken (C++)


Auf dieser Seite wird die aktuelle C++-Iterator-Unterstützung für Delphi-Aufzählungstypen und -Container beschrieben. Die folgende Tabelle enthält eine Übersicht über die unterstützten Typen und Container:

Container Iterator-Typ Iterator Traits BCC Clang Typ Bereichsbasiertes for Unterstützung für STL <algorithm> begin(), end()
System::DynamicArray<T> System::DynamicArray<T>::iterator random_access_iterator
Checkmark.svg
Checkmark.svg
Per Referenz (lesen, schreiben)
Checkmark.svg
(Nur Clang)
Vollständig Member, kein Member
TCollection (d. h. TList) System::TRandomIterator<T,E> random_access_iterator
Checkmark.svg
Per Wert (Nur lesen)
Checkmark.svg
(Nur Clang)
Nur nicht modifizierend Kein Member
TEnumerable System::TEnumerableIterator<T> input_iterator
Checkmark.svg
Per Wert (Nur lesen)
Checkmark.svg
(Nur Clang)
Nicht modifizierend, Nicht wahlfrei Kein Member
TCollection (nicht TDictionary) System::TBackInsertIterator<T> back_insert_iterator
Checkmark.svg
Ausgabe-Iterator Nur schreiben (siehe unten) n/v
TCollection (nicht TDictionary) System::TInsertIterator<T> front_insert_iterator,insert_iterator
Checkmark.svg
Ausgabe-Iterator Nur schreiben (siehe unten) n/v

Richtlinien

Die meisten Iteratoren werden vom System definiert und werden als Templates vom Compiler durch ADL und SFINAE ausgewählt. Das bedeutet, dass sie mit den meisten Typen funktionieren, aber bei ungewöhnlichen Interfaces oder ungewöhnlichem Verhalten in Ihren eigenen Typen könnte das Schreiben eines Iterators erforderlich sein. TDictionary unterstützt, obwohl es ein Aufzählungstyp ist, keinen wahlfreien Zugriff an einem Index und kann deshalb random_access_iterator nicht verwenden. Für TDictionary ist ein eigener Iterator definiert. Die folgenden Richtlinien dienen als Faustregel dafür, welche Iteratoren für einen Typ verwendet werden können.

  • Wenn der Typ nur eine GetEnumerator()-Methode hat, können Sie das bereichsbasierte for und eine begrenzte Anzahl von schreibgeschützten STL-Algorithmen verwenden.
  • Wenn der Typ einen Indizierungsoperator (operator[]) hat, können Sie das bereichsbasierte for und alle schreibgeschützten STL-Algorithmen verwenden.
Hinweis: TDictionary ist indizierbar, aber lässt keinen wahlfreien Zugriff zu. Es ist ein TEnumerable.
  • Wenn der Typ eine Art von System::DynamicArray<T> ist, können Sie das bereichsbasierte for und alle STL-Algorithmen verwenden. Beachten Sie, dass viele Delphi-RTL-Type "Aliase" für System::DynamicArray<T>, wie Arrayofstring, TIntegerDynArray, TStringDynArray und viele andere, sind.

DynamicArray<T>::iterator

DynamicArray<T>::iterator ist definiert als ein interner Typ von DynamicArray<T>; daher implementiert er begin() und end() als Member-Funktionen. Die restlichen unterstützten Iteratoren verfügen nicht über dieses Merkmal, weil sie Wrapper über Delphi-Klassen mit automatisch erzeugten Headern sind; dies bedeutet, dass Sie diesen Iterator mit BCC verwenden können.

System::DynamicArray<int> a(10,20,20,30);
System::DynamicArray<int>::iterator iter = a.begin();
while (iter != a.end()) {
  std::cout << *iter << std::endl;
  ++iter;
}

Die durch Clang erweiterten Compiler ermöglichen die Verwendung der bereichsbasierten for-Syntax:

System::DynamicArray<int> a({10,20,30,40,50});
for(int value: a) {
  std::cout << value << std::endl;
}

Das Hauptmerkmal dieses Iterators besteht darin, dass er den Zugriff auf Elemente per Referenz zulässt; das bedeutet, dass Sie den Inhalt eines DynamicArray mit einem Iterator ändern und die volle Leistung von STL-Algorithmen nutzen können.

/* This snippet uses STL Algorithms, remember to add '#include <algorithm>' at the beginning of your file  */
 
System::DynamicArray<int> a({10,20,30,40,50});
 
System::DynamicArray<int>::iterator iter = a.begin();
iter[0] = -30;
  
// Lambdas support is Clang-only 
// We can use functors in BCC
std::for_each(a.begin(),a.end(),[](int value){
  std::cout << value << std::endl;
});
  
std::random_shuffle(a.begin(),a.end());
std::sort(a.begin(),a.end());
Hinweis: Wenn in BCC RTTI deaktiviert ist (über IDE-Compiler-Optionen oder #pragma), generiert BCC E2366. Sie können die Datei compilieren, indem Sie die Iterator-Unterstützung deaktivieren. Fügen Sie diesen Code vor der ersten #include-Direktive in die CPP-Datei ein, die den Fehler auslöst.
#define NO_SYSDYN_ITERATOR

TRandomIterator::<T,E>

TRandomIterator::<T,E> ist für jeden RTL-Container definiert, der den Integer-Indizierungsoperator E operator[ ](int) und eine Integer-Count-Eigenschaft implementiert. Der Hauptunterschied zu DynamicArray-Iteratoren ist, dass Sie auf Elemente nur per Referenz zugreifen können, wenn E ein Referenztyp ist. Die meisten automatisch erzeugten HPP-Header definieren operator[] mit einem Werterückgabetyp wie TList,TStringList oder TStrings; dies bedeutet auch, dass Sie operator->() nicht für einen Iterator verwenden können, um auf Felder zuzugreifen, oder modifizierende STL-Algorithmen wie std::sort verwenden können.

Da es sich hier um einen Iterator-Wrapper handelt, der außerhalb des Containers definiert ist, müssen Sie die Nicht-Member-Funktionen begin() und end() verwenden, um ihn zu aktivieren:

TList *foo = new TList();
auto it = begin(foo);

Die eigentliche Implementierung von begin() und end() ist mit ADL und SFINAE definiert. BCC wird derzeit nicht unterstützt. In der Datei sysiterator.h finden Sie weitere Details.

TEnumerableIterator<T>

TEnumerableIterator::<T> ist für jeden Delphi-RTL-Container definiert, der die Methode GetEnumerator() implementiert. Der zurückgegebene Aufzählungstyp muss auch die Methoden GetCurrent() und MoveNext() unterstützen. Dieses Muster wird in RTL-Code häufig verwendet, daher betrifft es einen Großteil von Containern. TEnumerableiterator und TRandomITerator sind Eingabe-Iteratoren; das bedeutet, dass sie schreibgeschützt und nur vorwärts ausgerichtet sind und mit den Nicht-Member-Funktionen begin() und end() implementiert werden, daher sind sie nur für Clang-basierte Compiler aktiviert. Folgende Merkmale werden unterstützt:

Ein wichtiger Operator, der in TEnumerator fehlt, ist der Iterator für den Abstand (std::distance); daher stehen einige Algorithmen, die mit diesem Iterator arbeiten, wie std::binary_search oder std::count, nicht zur Verfügung.

Einfügungs-Iteratoren

Bestimmte Container können nicht geändert werden, aber Sie können Elemente einfügen und entfernen, indem Sie mit dem Konzept der Einfügungs-Iteratoren (EN) Kopien von STL-Iteratoren für RTL-Container und umgekehrt erstellen. Erstellen Sie derartige Iteratoren mit den folgenden benutzerdefinierten Funktionen:

  • System::back_inserter<T>(T *container)
  • System::front_inserter<T>(T *container)
  • System::make_inserter<T>(T *container, size_t place)
// This code uses STL Algorithms
// Remember to '#include <algorithm>'
 
std::vector<UnicodeString> v{"A","B","C","D","E"};
TStringList *list = new TStringList;
TStringList *list2 = new TStringList;
  
std::copy(v.begin(),v.end(),back_inserter(list)); // list == A, B, C, D, E
std::copy(v.begin(),v.end(),front_inserter(list2)); // list2 == E, D, C, B, A
std::copy(v.begin(),v.end(),make_inserter(list2,1)); // list2 == E, E, D, C,B, A, D, C, B, A
  
std::vector<UnicodeString> filtered;
// Copy only items from list2 that equal "C"
std::copy_if(begin(list2),end(list2),std::back_inserter(filtered),[](const UnicodeString &str){
  return "C" == str;   
});
// filtered == C,C

Siehe auch