C++/CX プログラムでは、標準テンプレート ライブラリ (STL) コンテナー、または他の任意のユーザー定義コレクション型を自由に使用できます。 ただし、XAML コントロールまたは JavaScript クライアントに渡す場合など、Windows ランタイム アプリケーション バイナリ インターフェイス (ABI) 間で双方向にコレクションを渡す場合は、Windows ランタイム コレクション型を使用する必要があります。
Windows ランタイムはコレクションおよび関連する型のインターフェイスを定義し、C++/CX は collection.h ヘッダー ファイルで具象 C++ 実装を提供します。 この図は、コレクション型間のリレーションシップを示しています。
Platform::Collections::VectorViewクラス とPlatform::Collections::MapViewクラス は、VectorとMapの読み取り専用バージョンです。反復子は、
Platform::Collections名前空間で定義されます。 これらの反復子は、STL 反復子の要件を満たし、任意のstd::findインターフェイス型またはstd::count_if具象型でWindows::Foundation::Collections、Platform::Collections、およびその他の STL アルゴリズムを使用できるようにします。 これは、たとえば、C# で作成された Windows ランタイム コンポーネントで 1 つのコレクションを繰り返して、それに STL アルゴリズムを適用できることを意味します。Important
プロキシ反復子
VectorIteratorとVectorViewIteratorは、プロキシ オブジェクトVectorProxy<T>とArrowProxy<T>を利用して、STL コンテナーでの使用を有効にします。 詳細については、この記事で後述する VectorProxy 要素 を参照してください。C++/CX コレクション型は、STL コンテナーがサポートしているのと同じスレッド セーフの保証をサポートしています。
Windows::Foundation::Collections::IObservableVectorWindows::Foundation::Collections::IObservableMapコレクションがさまざまな方法で変更されたときに発生するイベントを定義します。 これらのインターフェイスを実装することで、Platform::Collections::MapとPlatform::Collections::Vectorは XAML コレクションを使用したデータ バインドをサポートします。 たとえば、Vectorにデータ バインドされているGridがある場合、コレクションに項目を追加すると、変更がグリッド UI に反映されます。
ベクターの使用法
クラスがシーケンス コンテナーを別の Windows ランタイム コンポーネントに渡す必要がある場合は、パラメーターまたは戻り値の型として Windows::Foundation::Collections::IVector<T> を使用し、具体的な実装として Platform::Collections::Vector<T> します。 パブリックの戻り値またはパラメーターで Vector 型を使用しようとすると、コンパイラ エラー C3986 が発生します。 このエラーは、 Vector を IVectorに変更することで解決できます。
Important
独自のプログラム内のシーケンスを渡している場合は、 Vector か std::vector のどちらかを使用します。それらの方が IVectorより効率的であるためです。 ABI を介してコンテナーを渡す場合にのみ、 IVector を使用します。
Windows ランタイムの型システムは、ジャグ配列の概念をサポートしていないため、IVector<Platform::Array<T>> を戻り値またはメソッド パラメーターとして渡すことはできません。 ABI を通じてジャグ配列またはシーケンスのシーケンスを渡すには、 IVector<IVector<T>^>を使用します。
Vector<T> は、コレクションでの項目の追加、削除、およびアクセスに必要なメソッドを提供します。暗黙的に IVector<T>に変換可能です。
Vector<T>のインスタンスで STL アルゴリズム使用することもできます。 次の例は、基本的な使用法をいくつか示しています。
ここでbegin関数とend関数は、Platform::Collections名前空間ではなく、std名前空間から取得されます。
#include <collection.h>
#include <algorithm>
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation::Collections;
void Class1::Test()
{
Vector<int>^ vec = ref new Vector<int>();
vec->Append(1);
vec->Append(2);
vec->Append(3);
vec->Append(4);
vec->Append(5);
auto it =
std::find(begin(vec), end(vec), 3);
int j = *it; //j = 3
int k = *(it + 1); //or it[1]
// Find a specified value.
unsigned int n;
bool found = vec->IndexOf(4, &n); //n = 3
// Get the value at the specified index.
n = vec->GetAt(4); // n = 3
// Insert an item.
// vec = 0, 1, 2, 3, 4, 5
vec->InsertAt(0, 0);
// Modify an item.
// vec = 0, 1, 2, 12, 4, 5,
vec->SetAt(3, 12);
// Remove an item.
//vec = 1, 2, 12, 4, 5
vec->RemoveAt(0);
// vec = 1, 2, 12, 4
vec->RemoveAtEnd();
// Get a read-only view into the vector.
IVectorView<int>^ view = vec->GetView();
}
std::vector を使用する既存のコードがあり、それを Windows ランタイム コンポーネントで再使用する場合は、Vector または反復子のペアを取る std::vector コンストラクターの 1 つを使用して、ABI を介してコレクションを渡すポイントに Vector を構築します。 次の例は、 Vector からの効率的な初期化のために std::vector移動コンストラクターを使用する方法を示しています。 移動操作の後、元の vec 変数は有効でなくなります。
//#include <collection.h>
//#include <vector>
//#include <utility> //for std::move
//using namespace Platform::Collections;
//using namespace Windows::Foundation::Collections;
//using namespace std;
IVector<int>^ Class1::GetInts()
{
vector<int> vec;
for(int i = 0; i < 10; i++)
{
vec.push_back(i);
}
// Implicit conversion to IVector
return ref new Vector<int>(std::move(vec));
}
今後のいつか、ABI を介して渡す必要がある文字列ベクターがある場合、その文字列を最初に std::wstring 型として作成するのかそれとも Platform::String^ 型として作成するのかを決定する必要があります。 その文字列に対して多くの処理を実行する必要がある場合、 wstringを使用します。 それ以外の場合は、文字列を Platform::String^ 型として作成して、後で変換するコストを回避してください。 また、これらの文字列を std::vector と Platform::Collections::Vector のどちらに内部的に埋め込むのかも決定する必要があります。 一般に、 std::vector を使用し、ABI を介してコンテナーを渡す場合にのみ、そこから Platform::Vector を作成します。
ベクターにおける値の型
Platform::Collections::Vectorに格納する要素は、暗黙的に、または指定したカスタム std::equal_to比較子を使用して、等価比較をサポートする必要があります。 すべての参照型とすべてのスカラー型は、暗黙的に等値比較をサポートしています。
Windows::Foundation::DateTimeなどの非スカラー値型、またはカスタム比較 (objA->UniqueID == objB->UniqueIDなど) の場合は、カスタム関数オブジェクトを指定する必要があります。
VectorProxy 要素
Platform::Collections::VectorIteratorとPlatform::Collections::VectorViewIteratorは、range forコンテナーでstd::sortのようなループやIVector<T>アルゴリズムを使用することを可能にします。 ただし、 IVector 要素には C++ ポインター逆参照を使用してアクセスすることはできません。 GetAt メソッドと SetAt メソッドを介してのみアクセスできます。 したがって、これらの反復子は、標準ライブラリの要求に応じて、Platform::Details::VectorProxy<T>、Platform::Details::ArrowProxy<T>、および*演算子を介して個々の要素へのアクセスを提供するために、->および[]プロキシ クラスを使用します。 厳密には、 IVector<Person^> vecが指定されている場合、 *begin(vec) の型は VectorProxy<Person^>になります。 ただし、プロキシ オブジェクトは、ほとんどの場合、コードに対して透過的です。 これらのプロキシ オブジェクトは反復子によって内部でのみ使用されるため文書化されませんが、その機構の動作がわかっていると便利です。
for コンテナーに対して範囲ベースの IVector ループを使用する場合は、auto&& を使用して反復子変数が VectorProxy 要素に正しくバインドされるようにします。
auto& を使用すると、コンパイラの警告 C4239 が発生し、警告テキストに VectorProxy が示されます。
range for に対する IVector<Person^>ループ処理の例を次に示します。 実行が 64 行のブレークポイントで停止していることに注意してください。
[クイック ウォッチ] ウィンドウには、反復子変数 p が実際には VectorProxy<Person^> メンバー変数と m_v メンバー変数を持つ m_i であることが示されています。 ただし、この変数で GetType を呼び出すと、 Person インスタンス p2と同一の型が返されます。
VectorProxy と ArrowProxy が [クイック ウォッチ]、デバッガーの一部のコンパイラ エラー、またはその他の場所に表示される場合でも、通常はそれらについて明示的にコーディングする必要はありません。
プロキシ オブジェクトに関してコーディングする必要があるのは、 dynamic_cast 要素コレクションで特定の型の XAML オブジェクトを探している場合など、要素で UIElement を実行する必要がある場合です。 この場合、最初に要素を Platform::Object^ にキャストしてから、動的キャストを実行する必要があります。
void FindButton(UIElementCollection^ col)
{
// Use auto&& to avoid warning C4239
for (auto&& elem : col)
{
Button^ temp = dynamic_cast<Button^>(static_cast<Object^>(elem));
if (nullptr != temp)
{
// Use temp...
}
}
}
マップの使用状況
この例では、アイテムを挿入してPlatform::Collections::Mapで検索し、読み取り専用のMap型としてWindows::Foundation::Collections::IMapViewを返す方法を示します。
//#include <collection.h>
//using namespace Platform::Collections;
//using namespace Windows::Foundation::Collections;
IMapView<String^, int>^ Class1::MapTest()
{
Map<String^, int>^ m = ref new Map<String^, int >();
m->Insert("Mike", 0);
m->Insert("Dave", 1);
m->Insert("Doug", 2);
m->Insert("Nikki", 3);
m->Insert("Kayley", 4);
m->Insert("Alex", 5);
m->Insert("Spencer", 6);
// PC::Map does not support [] operator
int i = m->Lookup("Doug");
return m->GetView();
}
一般に、内部マップ機能については、パフォーマンス上の理由で std::map 型を優先します。 ABI 経由でコンテナーを渡す必要がある場合は、Platform::Collections::Mapからstd::mapを作成し、MapをWindows::Foundation::Collections::IMapとして返します。 パブリックの戻り値またはパラメーターで Map 型を使用しようとすると、コンパイラ エラー C3986 が発生します。 このエラーは、 Map を IMapに変更することで解決できます。 たとえば、実行するルックアップや挿入の数が多くなく、ABI を介して頻繁にコレクションを渡すなどの場合、最初から Platform::Collections::Map を使用し std::mapを変換するコストを回避した方がコストを抑えられることがあります。 どちらの場合も、 IMap のルックアップ操作と挿入操作は、3 つの種類で最もパフォーマンスが低いので避けます。 ABI を介してコンテナーを渡すポイントでのみ、 IMap に変換します。
マップにおける値の型
Platform::Collections::Map内の要素は順序付けされます。
Mapに格納する要素は、暗黙的に、または指定したカスタムstd::less比較子を使用して、厳密な弱い順序付けとの比較よりも少ない比較をサポートする必要があります。 スカラー型では、この比較を暗黙的にサポートしています。
Windows::Foundation::DateTimeなどの非スカラー値型、またはカスタム比較 ( objA->UniqueID < objB->UniqueIDなど) の場合、カスタム比較子を提供する必要があります。
コレクションの種類
コレクションは、シーケンス コレクションと関連コレクションそれぞれの変更可能バージョンと読み取り専用バージョンという 4 つのカテゴリに分類されます。 さらに、C++/CX は、コレクションのアクセスを簡単にする 3 つの反復子クラスを提供することによりコレクションを拡張します。
変更可能なコレクションの要素は変更できますが、 ビューと呼ばれる読み取り専用コレクションの要素は読み取りしか実行できません。
Platform::Collections::VectorまたはPlatform::Collections::VectorView コレクションの要素には、反復子またはコレクションのVector::GetAtとインデックスを使用してアクセスできます。 連想コレクションの要素には、コレクションの Map::Lookup とキーを使用してアクセスできます。
Platform::Collections::Map クラス
変更可能な関連コレクション。 マップ要素は、キーと値のペアです。 キーを検索してその関連付けられた値を取得することと、キーと値のペアをすべて繰り返すことの両方がサポートされています。
Map と MapView は、 <K, V, C = std::less<K>>で template 宣言されるので、比較子をカスタマイズできます。 さらに、 Vector と VectorView は <T, E = std::equal_to<T>> で template 宣言されるので、 IndexOf()の動作をカスタマイズできます。 これは、値の構造体の Vector と VectorView について特に重要です。 たとえば、 Vector<Windows::Foundation::DateTime>を作成するには、DateTime が == 演算子をオーバーロードしないため、カスタム 比較子を指定する必要があります。
Platform::Collections::MapView クラス
Mapの読み取り専用バージョン。
Platform::Collections::Vector クラス
変更可能なシーケンス コレクション。
Vector<T> では、定数時間ランダム アクセスと償却定数時間 Append 操作がサポートされています。
Platform::Collections::VectorView クラス
Vectorの読み取り専用バージョン。
Platform::Collections::InputIterator クラス
STL 入力反復子の要件を満たす STL の反復子。
Platform::Collections::VectorIterator クラス
変更可能な STL ランダム アクセス反復子の要件を満たす STL 反復子。
Platform::Collections::VectorViewIterator クラス
STL の const ランダム アクセス反復子の要件を満たす STL 反復子。
begin() および end() 関数
STL を使用して、 Vector、 VectorView、 Map、 MapView、および任意の Windows::Foundation::Collections オブジェクトを処理するために、C++/CX では、 begin 関数 と end 関数 の非メンバー関数のオーバーロードがサポートされています。
次の表は、使用できる反復子と関数の一覧を示しています。
| Iterators | Functions |
|---|---|
Platform::Collections::VectorIterator<T>(内部的に Windows::Foundation::Collections::IVector<T> と intを格納します。 |
begin
/
end(Windows::Foundation::Collections::IVector<T>) |
Platform::Collections::VectorViewIterator<T>(内部的に IVectorView<T>^ と int を格納します。 |
begin
/
end (IVectorView<T>^) |
Platform::Collections::InputIterator<T>(内部的に IIterator<T>^ と T を格納します。 |
begin
/
end (IIterable<T>) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>(内部的に IIterator<T>^ と T を格納します。 |
begin
/
end (IMap<K,V>) |
Platform::Collections::InputIterator<IKeyValuePair<K, V>^>(内部的に IIterator<T>^ と T を格納します。 |
begin
/
end (Windows::Foundation::Collections::IMapView) |
コレクション変更イベント
Vector と Map は、XAML コレクションでのデータ バインドをサポートしていますが、これは、コレクション オブジェクトが変更またはリセットされたとき、またはコレクションのいずれかの要素が挿入、削除、または変更されたときに発生するイベントを実装することで実現されています。 データ バインドをサポートする独自の型を作成できます。ただし、 Map と Vector から継承することはできません。これらの型はシールされているためです。
Windows::Foundation::Collections::VectorChangedEventHandlerおよびWindows::Foundation::Collections::MapChangedEventHandlerデリゲートは、コレクション変更イベントのイベント ハンドラーのシグネチャを指定します。
Windows::Foundation::Collections::CollectionChangeパブリック列挙型クラス、および Platform::Collections::Details::MapChangedEventArgs および Platform::Collections::Details::VectorChangedEventArgs ref クラスは、イベントの原因を特定するためにイベント引数を格納します。
*EventArgs 型は Details 名前空間で定義されますが、これは、Map か Vector を使用するときには、それらを明示的に作成および利用する必要がないためです。