コレクション (C++/CX)
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 反復子の要件を満たし、任意の Windows::Foundation::Collections インターフェイス型や Platform::Collections 具象型で std::find、std::count_if などの STL アルゴリズムを使えるようにします。 これは、たとえば、C# で作成された Windows ランタイム コンポーネントで 1 つのコレクションを繰り返して、それに STL アルゴリズムを適用できることを意味します。
重要
プロキシ反復子
VectorIterator
とVectorViewIterator
は、プロキシ オブジェクトVectoryProxy<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
に変更することで解決できます。
重要
独自のプログラム内のシーケンスを渡している場合は、 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 ランタイム コンポーネントで再使用する場合は、std::vector
または反復子のペアを取る 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 により、IVector<T> コンテナーで range for
ループや std::sort などのアルゴリズムを使えるようになります。 ただし、C++ ポインターの逆参照を使って IVector
要素にアクセスすることはできません。これらの要素には、 GetAt メソッドと SetAt メソッドを使ってアクセスすることしかできません。 したがって、これらの反復子は、標準ライブラリの要求に従って、プロキシ クラス Platform::Details::VectorProxy<T>
および Platform::Details::ArrowProxy<T>
を使用して *、->、[] の各演算子を介した個々の要素へのアクセスを提供します。 厳密には、 IVector<Person^> vec
が指定されている場合、 *begin(vec)
の型は VectorProxy<Person^>
になります。 ただし、プロキシ オブジェクトは、ほとんどの場合、コードに対して透過的です。 これらのプロキシ オブジェクトは反復子によって内部でのみ使用されるため文書化されませんが、その機構の動作がわかっていると便利です。
for
コンテナーに対して範囲ベースの IVector
ループを使用する場合は、auto&&
を使用して反復子変数が VectorProxy
要素に正しくバインドされるようにします。 auto&
を使用すると、コンパイラの警告 C4239 が発生し、警告テキストに VectoryProxy
が示されます。
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 を介してコンテナーを渡す必要がある場合は、 std::map から Platform::Collections::Map を構築し、 Map
を Windows::Foundation::Collections::IMapとして返します。 パブリックの戻り値またはパラメーターで Map
型を使用しようとすると、コンパイラ エラー C3986 が発生します。 このエラーは、 Map
を IMap
に変更することで解決できます。 たとえば、実行するルックアップや挿入の数が多くなく、ABI を介して頻繁にコレクションを渡すなどの場合、最初から Platform::Collections::Map
を使用し std::map
を変換するコストを回避した方がコストを抑えられることがあります。 どちらの場合も、 IMap
のルックアップ操作と挿入操作は、3 つの種類で最もパフォーマンスが低いので避けます。 ABI を介してコンテナーを渡すポイントでのみ、 IMap
に変換します。
マップにおける値の型
Platform::Collections::Map 内の要素は、順序付きです。 Map
に格納しようとする要素は、厳密な弱い順序付けに基づき、"より小さい" 比較をサポートする必要があります。このために、暗黙的な比較、または開発者が指定したカスタム比較子 stl::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>
は、定数時間ランダム アクセス操作と償却定数時間の 追加 操作をサポートしています。
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 関数という非メンバー関数のオーバーロードをサポートしています。
次の表は、使用できる反復子と関数の一覧を示しています。
反復子 | 関数 |
---|---|
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::Collection::Details::MapChangedEventArgs
、 Platform::Collections::Details::VectorChangedEventArgs
ref クラスは、イベントの原因を特定するためにイベント引数を格納します。 *EventArgs
型は Details
名前空間で定義されますが、これは、Map
か Vector
を使用するときには、それらを明示的に作成および利用する必要がないためです。