SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

C++/CLIのSTL/CLR オブジェクトにC#からアクセスする方法

STL/CLRと.NET Frameworkの連携

イテレータ

 STL では、コンテナが要素をどのように管理しているかに依存することなく、外部からコンテナの要素を操作できるように、イテレータ(反復子)を提供しました。STL/CLR の場合も、基本的な構造は同じです。vector クラスのようなコンテナは begin() メソッドで先頭の要素を指すイテレータを返し、end() メソッドで末尾の次の要素を指すイテレータを返します。外部のコードから STL/CLR に依存するイテレータ型を利用するメリットはそれほどありませんが、インターフェイスを通してイテレータを操作することができます。

 これらのメソッドが返すイテレータ型は、コンテナの iterator メンバとして公開されています。例えば、vector クラスの iterator メンバは Microsoft のドキュメントで次のように記載されています。

vector クラス iterator 型定義 (C++/CLI)
typedef T1 iterator;

 イテレータ型の実体は隠蔽されていますが、vector ファイル内のクラスの宣言を見ると RandomAccessIterator クラスが使われています。

cliext::RandomAccessIterator 構造体 (C++/CLI)
template<typename _Cont_t>
    value class RandomAccessIterator
    :    public _STLCLR Generic::IRandomAccessIterator<
            typename _Cont_t::value_type>

Microsoft.VisualC.StlClr.Generic.IRandomAccessIterator インターフェイス

 宣言からもお分かりいただけるように、イテレータ型もテンプレートでコンパイル時に展開されるため、コンパイル後に他の言語からイテレータ型を直接利用することはできません。そこで、コンテナと同じように RandomAccessIterator が実装している Microsoft.VisualC.StlClr.Generic.IRandomAccessIterator インターフェイスを使います。

Microsoft.VisualC.StlClr.Generic.IRandomAccessIterator インターフェイス (C#)
public interface IRandomAccessIterator<TValue> : IBidirectionalIterator<TValue>

 TValue には、このイテレータが扱う要素の型を表します。vector クラスの begin() メソッドや end() メソッドが返すイテレータは、IRandomAccessIterator インターフェイス型として利用できます。Microsoft.VisualC.StlClr.Generic 名前空間では、STL で定められているイテレータの種類に対応したインターフェイスを宣言しています。すべてのイテレータは、IBaseIterator インターフェイスを基底に実装しています。

  • イテレータ: IBaseIterator
  • 入力イテレータ: IInputIterator (IBaseIterator を継承)
  • 出力イテレータ: IOutputIterator (IBaseIterator を継承)
  • 前方イテレータ: IForwardIterator (IInputIteratorIOutputIterator を継承)
  • 双方向イテレータ: IBidirectionalIterator (IForwardIterator を継承)
  • ランダムアクセスイテレータ: IRandomAccessIterator (IBidirectionalIterator を継承)

 最も自由度の高いランダムアクセスイテレータは、他のすべてのイテレータの機能を持ちます。ただし、これらのイテレータ型は IEnumerable を実装しないため、.NET Framework アプリケーションから直接操作するには適さないでしょう。イテレータを利用するのは C++/CLI の中で行い、イテレータの受け渡しなど、中間的な操作を他の言語で行う必要がある場合などで応用する程度です。また、他の言語から、イテレータの要素にアクセスすることはできません。

 イテレータを次の要素に進めるには IBaseIterator インターフェイスの next() メソッドを使います。この操作は、C++ 言語におけるイテレータのインクリメント処理と同じです。

IBaseIterator インターフェイス next() メソッド (C#)
void next()

 同じように、後方移動可能な IBidirectionalIterator インターフェイスであれば prev() メソッドから前の要素に移動できます。イテレータのデクリメント処理と同じです。

IBidirectionalIterator インターフェイス prev() メソッド (C#)
void prev()

 さらに、ランダムアクセス可能な IRandomAccessIterator インターフェイスであれば move() メソッドが使えます。

IRandomAccessIterator インターフェイス move() メソッド (C#)
int move(int _Offset)

 このメソッドの _Offset パラメータには、現在の要素から移動する要素数を指定します。正数を指定した場合は前へ、負数を指定した場合は後ろに移動します。

 また、イテレータが指す要素へアクセスするためのメソッドとして、IInputIterator インターフェイスでは定数参照を返す get_cref() メソッドが、IOutputIterator インターフェイスでは参照を返す get_ref() メソッドが公開されています。しかし、これらのメソッドは、戻り値型に C++/CLI に依存した追跡参照を用いるため C# や Visual Basic などの他の言語から呼び出すことはできません。

vector オブジェクトのイテレータを返す DataManager クラス( C++/CLI )

 では、最初に C++/CLI で vector<int> オブジェクトから取得したイテレータを IRandomAccessIterator<int> 型として返すライブラリを作りましょう。

Sample05 C++/CLI
#include <cliext/vector>
#using <mscorlib.dll>

using namespace System;
using namespace cliext;
using namespace Microsoft::VisualC::StlClr::Generic;

public ref class DataManager {
private:
    vector<int>^ container;
public:
    DataManager(int min, int max);
    IRandomAccessIterator<int>^ GetBegin();
    IRandomAccessIterator<int>^ GetEnd();
    int GetValue(IRandomAccessIterator<int>^ iterator);
};

DataManager::DataManager(int min, int max) {
    container = gcnew vector<int>();

    for (int i = min ; i < max ; i++)
        container->push_back(i);
}

IRandomAccessIterator<int>^ DataManager::GetBegin() {
    return container->begin();
}

IRandomAccessIterator<int>^ DataManager::GetEnd() {
    return container->end();
}

int DataManager::GetValue(IRandomAccessIterator<int>^ iterator) {
    return iterator->get_cref();
}

 Sample05 は、内部で生成した vector オブジェクトのイテレータを返す DataManager クラスを作成したものです。要素の先頭を指すイテレータは GetBegin() メソッドから、要素の末尾の次を指すイテレータは End() メソッドから取得できます。また、C# 言語で作成したコードが値を受け取れるように、get_cref() メソッドの追跡参照を値として返す GetValue() メソッドも用意しています。これは、C# 側で値を確認するためのものですが、実践ではこのような遠まわしで奇妙な設計を使うことはないでしょう。

次のページ
関数オブジェクト

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

赤坂 玲音(アカサカ レオン)

平成13年度「全国高校生・専門学校生プログラミングコンテスト 高校生プログラミングの部」にて最優秀賞を受賞。2005 年度~ Microsoft Most Variable Professional Visual Developer - Visual C++。プログラミング入門サイト WisdomSoft の管理人。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2474 2008/05/20 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー