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::IObservableVector
Windows::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
を使用するときには、それらを明示的に作成および利用する必要がないためです。