コレクション (C++/CX)

C++/CX プログラムでは、標準テンプレート ライブラリ (STL) コンテナー、または他の任意のユーザー定義コレクション型を自由に使用できます。 ただし、XAML コントロールまたは JavaScript クライアントに渡す場合など、Windows ランタイム アプリケーション バイナリ インターフェイス (ABI) 間で双方向にコレクションを渡す場合は、Windows ランタイム コレクション型を使用する必要があります。

Windows ランタイムはコレクションおよび関連する型のインターフェイスを定義し、C++/CX は collection.h ヘッダー ファイルで具象 C++ 実装を提供します。 この図は、コレクション型間のリレーションシップを示しています。

Diagram of C plus plus C X inheritance tree for collection types.

ベクターの使用

クラスがシーケンス コンテナーを別の Windows ランタイム コンポーネントに渡す必要がある場合、Windows::Foundation::Collections:: IVector<T> をパラメーターや戻り値の型として使うか、Platform::Collections::Vector<T> を具象実装として使います。 パブリックの戻り値またはパラメーターで Vector 型を使用しようとすると、コンパイラ エラー C3986 が発生します。 このエラーは、 VectorIVectorに変更することで解決できます。

重要

独自のプログラム内のシーケンスを渡している場合は、 Vectorstd::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:vectorPlatform::Collections::Vector のどちらに内部的に埋め込むのかも決定する必要があります。 一般に、 std::vector を使用し、ABI を介してコンテナーを渡す場合にのみ、そこから Platform::Vector を作成します。

ベクターにおける値の型

Platform::Collections::Vector に格納される要素は、暗黙的にまたは指定したカスタム std::equal_to 比較子を使用するかして、等値比較をサポートする必要があります。 すべての参照型とすべてのスカラー型は、暗黙的に等値比較をサポートしています。 Windows::Foundation::DateTimeなどの非スカラー値型の場合や、カスタム比較 ( objA->UniqueID == objB->UniqueIDなど) の場合、カスタム関数オブジェクトを提供する必要があります。

VectorProxy 要素

Platform::Collections::VectorIteratorPlatform::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と同一の型が返されます。 VectorProxyArrowProxy[クイック ウォッチ]、デバッガーの一部のコンパイラ エラー、またはその他の場所に表示される場合でも、通常はそれらについて明示的にコーディングする必要はありません。

Screenshot of debugging VectorProxy in a range based for loop.

プロキシ オブジェクトに関してコーディングする必要があるのは、 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 を構築し、 MapWindows::Foundation::Collections::IMapとして返します。 パブリックの戻り値またはパラメーターで Map 型を使用しようとすると、コンパイラ エラー C3986 が発生します。 このエラーは、 MapIMapに変更することで解決できます。 たとえば、実行するルックアップや挿入の数が多くなく、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 クラス
変更可能な関連コレクション。 マップ要素は、キーと値のペアです。 キーを検索してその関連付けられた値を取得することと、キーと値のペアをすべて繰り返すことの両方がサポートされています。

MapMapView は、 <K, V, C = std::less<K>>で template 宣言されるので、比較子をカスタマイズできます。 さらに、 VectorVectorView<T, E = std::equal_to<T>> で template 宣言されるので、 IndexOf()の動作をカスタマイズできます。 これは、値の構造体の VectorVectorView について特に重要です。 たとえば、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 を使用した VectorVectorViewMapMapView、および任意の 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)

コレクション変更イベント

VectorMap は、XAML コレクションでのデータ バインドをサポートしていますが、これは、コレクション オブジェクトが変更またはリセットされたとき、またはコレクションのいずれかの要素が挿入、削除、または変更されたときに発生するイベントを実装することで実現されています。 データ バインドをサポートする独自の型を作成できます。ただし、 MapVector から継承することはできません。これらの型はシールされているためです。

Windows::Foundation::Collections::VectorChangedEventHandler デリゲートと Windows::Foundation::Collections::MapChangedEventHandler デリゲートは、コレクション変更イベントのイベント ハンドラーのシグネチャを指定します。 Windows::Foundation::Collections::CollectionChange パブリック列挙型クラス、 Platform::Collection::Details::MapChangedEventArgsPlatform::Collections::Details::VectorChangedEventArgs ref クラスは、イベントの原因を特定するためにイベント引数を格納します。 *EventArgs 型は Details 名前空間で定義されますが、これは、MapVector を使用するときには、それらを明示的に作成および利用する必要がないためです。

関連項目

型システム
C++/CX 言語リファレンス
名前空間参照