第2章で「配列のようなものに対するループ処理を行う関数テンプレート」といいました。この「のようなもの」と言ったのには意味があります。今回はそういうお話です。
では、今回の要点です。
では、いってみましょう。
いきなりですが、第2章で自作した min_element をもう一度よく見てみましょう。
template <typename TYPE> TYPE min_element(TYPE pBegin, TYPE pEnd) { TYPE pMin; for(TYPE p = pMin = pBegin; p != pEnd; ++p) if(*p < *pMin) pMin = p; return pMin; } |
この関数テンプレートに int 型の配列を渡すと、TYPE が int* に置き換わった関数が作られます。
int* min_element<int*>(int* pBegin, int* pEnd) { int* pMin; for(int* p = pMin = pBegin; p != pEnd; ++p) if(*p < *pMin) pMin = p; return pMin; } |
さて、ここで配列でもポインタでもなく、クラスを渡してみるとどうなるでしょうか? 例えばクラス名を CIterator とすると、
CIterator min_element<CIterator>(CIterator pBegin, CIterator pEnd) { CIterator pMin; for(CIterator p = pMin = pBegin; p != pEnd; ++p) if(*p < *pMin) pMin = p; return pMin; } |
という関数が作られることになります。
第2部第35章でやったように、置き換えた後にエラーさえ出なければテンプレートには何を渡してもいいのでした。では、今回の場合はどうなるでしょうか?
ここでの CIterator のインスタンスに対する操作というのは
の6つです。つまり、CIterator クラスがこの6つの操作に対してエラーを起こさなければアルゴリズムに渡せてしまうわけです。
では、実際に実験してみましょう。
プログラム |
---|
// Iter1.cpp #include <iostream> #include <algorithm> using namespace std; #define numof(array) (sizeof (array) / sizeof *(array)) class CIterator { private: int* m_p; public: CIterator(int* p) : m_p(p) { } // 値渡しと値返しは自動的に行われます // 代入 CIterator& operator=(const CIterator& it) { m_p = it.m_p; return *this; } // 比較 bool operator!=(const CIterator& it) { return (m_p != it.m_p); } // インクリメント(前置) CIterator& operator++() { m_p++; return *this; } // 参照 int& operator*() { return *m_p; } }; int main() { int data[] = { 4, 2, 9, 7, 1, }; CIterator itBegin(data), itEnd(data + numof(data)); cout << *min_element(itBegin, itEnd) << endl; return 0; } |
実行結果 |
1 |
見事アルゴリズムをだますのに成功しました。このように、アルゴリズムにはポインタと似たような動作をするクラスも渡すことができるわけです。このようなクラスのことをイテレータ(iterator:反復子)と呼びます。動詞 iterate は「繰り返す」という意味です。つまり、イテレータは繰り返しに使うためのクラスというわけです。
このイテレータが使えるということで、アルゴリズムは配列以外のもののループ処理にも利用できるというわけです。例えば、工夫すれば第3部第32章でやったリストのループ処理にも応用できそうですね。
では、今回の要点です。
次回からはコンテナについて話したいと思います。STLの便利さを強く実感するクラス群になると思います。それでは。
Last update was done on 2001.7.8
この講座の著作権はロベールが保有しています