Delphi の列挙型およびコンテナに対する C++ イテレータのサポート
RAD Studio ライブラリに対する言語サポート(C++) への移動
本ページでは、Delphi 列挙型とコンテナに対する現在の C++ イテレータ サポートについて説明します。次の表では、サポートされている型やコンテナの概要が記載されています:
目次
ガイドライン
大抵のイテレータはシステム定義されたもので、テンプレートは、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>
に対する「エイリアス」であることに留意してください(Arrayofstring
、TIntegerDynArray
、TStringDynArray
、やその他多数)。
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());
#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 コードで頻繁に使用されており、コンテナのかなりの部分をカバーしています。TEnumerableiterator
と TRandomITerator
は 入力イテレータです。つまり、これらは読み取り専用かつ前方専用で、非メンバーである begin()
と end()
を使用して実装されており、Clang ベースのコンパイラでのみ有効です。サポートされている機能は:
- Range-for
- 入力イテレータ上で操作する非変更 STL アルゴリズムで、次のようなもの:
-
- std::for_each
- std::find
- std::copy のソースとして
TEnumerator
で欠けている主な演算子が、イテレータ差分(std::distance)です。このため、イテレータ距離(std::binary_search や std::count など)に依存する一部のアルゴリズムは、利用できません。
コレクション列挙型の一部として、RAD Studio は、反復処理が完了した際に、列挙子の状態を正式に定義します: ”列挙子の状態は、MoveNext が False を返した後は無効であり、列挙子は解放または再度作成される必要があり、以降アクセスしてはなりません。”
挿入イテレータ
所定の位置にある一部のコンテナは変更できませんが、挿入イテレータの概念を利用して、新しい要素を挿入したり、要素を削除して、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