Delphi の列挙型およびコンテナに対する C++ イテレータのサポート

提供: RAD Studio
移動先: 案内検索

RAD Studio ライブラリに対する言語サポート(C++) への移動


本ページでは、Delphi 列挙型とコンテナに対する現在の C++ イテレータ サポートについて説明します。次の表では、サポートされている型やコンテナの概要が記載されています:

コンテナ イテレータ型 イテレータ特性 Bcc Clang Range-for STL <アルゴリズム> サポート begin()、end()
System::DynamicArray<T> System::DynamicArray<T>::iterator random_access_iterator
Allowed.png
Allowed.png
リファレンスによって(読み取り/書き込み)
Allowed.png
(Clang のみ)
すべて メンバー、非メンバー
TCollection (ie TList) System::TRandomIterator<T,E> random_access_iterator
Allowed.png
値によって(読み取り専用)
Allowed.png
(Clang のみ)
非編集のみ 非メンバー
TEnumerable System::TEnumerableIterator<T> input_iterator
Allowed.png
値によって(読み取り専用)
Allowed.png
(Clang のみ)
非編集、非ランダム 非メンバー
TCollection (no TDictionary) System::TBackInsertIterator<T> back_insert_iterator
Allowed.png
出力イテレータ 書き込みのみ(以下参照) N/A
TCollection (no TDictionary) System::TInsertIterator<T> front_insert_iterator、insert_iterator
Allowed.png
出力イテレータ 書き込みのみ(以下参照) N/A

ガイドライン

大抵のイテレータはシステム定義されたもので、テンプレートは、ADL や SFINAE によってコンパイラによって選択されます。これはつまり、イテレータが大半の型に対して動作しますが、自分が作成した独自の型における通常とは異なるインターフェイスや動作については、それに合わせてイテレータも記述する必要があるということです。たとえば TDictionary の場合、列挙可能なものであるとはいえ、インデックスの場所に対するランダム アクセスをサポートしていないため、random_access_iterator を使用することはできません。このため、独自のイテレータが定義されています。次は、ある型に対してどのイテレータが利用可能か、大まかに判断するのに使用できるガイドラインです。

  • その型が GetEnumerator() メソッドのみを持っていたら、Range-for と読み取り専用 STL アルゴリズムの制限セットを使用することができる。
  • その型が添字 演算子[] を持っていたら、Range-for と、すべての読み取り専用 STL アルゴリズムを使用することができる。
メモ: TDictionary が添字演算子が可能だか、ランダム アクセスは可能ではありません。それは TEnumerable です。
  • その型が、System::DynamicArray<T> の一種の場合、Range-for と STL アルゴリズムのフルセットを使用することができる。多くの Delphi RTL 型が System::DynamicArray<T> に対する「エイリアス」であることに留意してください(ArrayofstringTIntegerDynArrayTStringDynArray、やその他多数)。

DynamicArray<T>::iterator

DynamicArray<T>::iterator は、DynamicArray<T> のイテレータ型として定義されています。このため、begin()end() をメンバー関数として実装しています。残りのサポート イテレータはこの機能を持っていません。これらは、自動生成ヘッダーを持つ Delphi クラス周りのラッパーであるからです。これはつまり、このイテレータを BCC と共に使用できることを意味します。

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

Clang 拡張コンパイラにより、range-for 構文を使用することができます:

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

このイテレータの主要機能は、参照による要素へのアクセスを可能にしていることで、これはつまり、DynamicArray の内容をイテレータを使用して編集でき、STL アルゴリズムのフルパワーにアクセスすることができることを意味します。

/* 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());
メモ: RTTI が BCC で無効な場合(IDE コンパイラ オプションまたは #pragma を介して)、BCC は E2366 を生成します。イテレータ サポートを無効にすることで、ファイルをコンパイルできます。このコードを、エラーを起こす .cpp ファイルの #include 指令の前に追加します。
#define NO_SYSDYN_ITERATOR

TRandomIterator::<T,E>

TRandomIterator::<T,E> は、各 RTL コンテナに対して定義されています。コンテナでは、整数の添字演算子 E operator[ ](int) と、整数プロパティ Count が実装されています。DynamicArray イテレータとの主な違いは、E が参照型だった場合、参照でした項目にアクセスできない点です。自動生成された .hpp ヘッダーの多くでは、operator[] を値戻り値型(TList,TStringList or TStrings など)で定義しています。これはまた、フィールドにアクセスするために、operator->() をイテレータに対しては使用できず、std::sort といった変更 STL アルゴリズムも使用できないことを意味します。

これは、コンテナの外側で定義されたイテレータ ラッパーなので、有効にするためにはメンバーではない begin() およびend() を使用しなければなりません:

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

begin() および end() の実際の実装は、ADL および SFINAE を使用して定義されています。BCC は、現在サポートされていません。さらなる詳細については、sysiterator.h ヘッダーを参照してください。

TEnumerableIterator<T>

TEnumerableIterator::<T> は、GetEnumerator() メソッドを実装している Delphi RTL コンテナそれぞれに対して定義されています。返された列挙型は、メソッド GetCurrent() および MoveNext() をサポートしなければなりません。このパターンは、RTL コードで頻繁に使用されており、コンテナのかなりの部分をカバーしています。TEnumerableiteratorTRandomITerator入力イテレータです。つまり、これらは読み取り専用かつ前方専用で、非メンバーである begin()end() を使用して実装されており、Clang ベースのコンパイラでのみ有効です。サポートされている機能は:

  • Range-for
  • 入力イテレータ上で操作する非変更 STL アルゴリズムで、次のようなもの:

TEnumerator で欠けている主な演算子が、イテレータ差分(std::distance)です。このため、イテレータ距離(std::binary_search や std::count など)に依存する一部のアルゴリズムは、利用できません。

挿入イテレータ

所定の位置にある一部のコンテナは変更できませんが、挿入イテレータの概念を利用して、新しい要素を挿入したり、要素を削除して、STL イテレータから RTL コンテナへ、またはその逆にコピーを作成することはできます。それらイテレータを作成するには、次のカスタム関数を使用します:

  • 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

関連項目