お世話になっております、大変初歩的な質問かもしれませんがお願いします。
下記のサイト様を参考にイテレータとクラステンプレートの簡単な実装を試していてエラーが出たので、その理由について伺いたいのです。
http://program.station.ez-net.jp/specia ... r-make.asp
以下はヘッダファイル部分ですが、内容は至極単純なコンテナクラスとイテレータクラスをテンプレートにしただけのものです(200行近くあり冗長です、すみません)
エラーが出た場所は MyClassクラスの実装部分の "begin関数" と "end関数" の部分です。
► スポイラーを表示
コード:
#pragma once
#include <iterator>
//MyClassの定義中にMyClassIteratorの記述があるので不完全型を記述
template <typename T>class MyClassIterator;
/***************************************/
/* MyClassクラスの宣言 */
/***************************************/
template <typename T>class MyClass{
//MyClassIterator が privateメンバにアクセスできるようフレンド指定
friend MyClassIterator<T>;
//イテレーターに関する実装
public:
//MyClassIterator を インナークラスのように MyClass::Iterator として使えるようにする
typedef typename MyClassIterator<T> iterator;
//開始位置を示すイテレータを取得するメンバ関数
iterator begin();
//終了位置を示すイテレータを取得するメンバ関数
iterator end();
//イテレータ以外の通常の実装
private:
T m_serial;
public:
MyClass();
MyClass(const MyClass& myCls);
T getSerial() const;
};
/***************************************/
/* MyClassIteratorクラスの宣言 */
/***************************************/
template <typename T>class MyClassIterator : public std::iterator<std::forward_iterator_tag,T>{
//MyClass が privateなメンバを呼び出せるようにフレンド指定
friend MyClass<T>;
//値の場所を示すメンバ変数と、取り扱うMyClassへのポインタをprivateに格納
private:
size_t m_index;
MyClass<T> *m_myCls;
//MyClass(イテレータを利用するfriendクラス)がイテレータを作る為のコンストラクタ
//なのでprivateに格納して、それ以外の外部から勝手に作られないようにする
private:
MyClassIterator();
MyClassIterator(MyClass<T>* mycls, size_t index);
//コピーコンストラクタはpublicで呼び出せるようにしておく
public:
MyClassIterator(const MyClassIterator& iterator);
//フォワードイテレータで必要な実装を記述
public:
MyClassIterator& operator++();
MyClassIterator operator++(int);
T& operator*();
bool operator==(const MyClassIterator& iterator);
bool operator!=(const MyClassIterator& iterator);
};
/***************************************/
/* MyClassIteratorクラスの実装 */
/***************************************/
//デフォルトコンストラクタは末端に相当するイテレータを作成
template<typename T>
MyClassIterator<T>::MyClassIterator(){
m_myCls = nullptr;
m_index = SIZE_MAX;
}
//扱うインスタンスと最初の位置情報を受け取ってイテレータを作成
template<typename T>
MyClassIterator<T>::MyClassIterator(MyClass<T>* myCls, size_t index){
m_myCls = myCls;
//今回は位置情報が最初(m_serial)か末端(SIZE_MAX)しかないため、それ(0)以外の値は置き換える
m_index = (index == 0 ? index : SIZE_MAX);
}
//コピーコンストラクタでは既に作られているイテレータの値を複製するだけなのでpublic
template<typename T>
MyClassIterator<T>::MyClassIterator(const MyClassIterator& iterator){
m_myCls = iterator.m_myCls;
m_index = iterator.m_index;
}
//間接参照演算子の実装(今回は読み書き可能なイテレータなので参照を返す)
template<typename T>
T& MyClassIterator<T>::operator*(){
//MyClassクラスでfriend指定されているのでprivateメンバに直接アクセス可能
//末端の位置だった場合は書き換えられると困るので今回はダミーに置き換える
static T dummy;
return (m_index != SIZE_MAX ? m_myCls->m_serial : dummy);
}
//イテレータの加算ではイテレータが次の位置を示すように内部情報を書き換える
template<typename T>
MyClassIterator<T>& MyClassIterator<T>::operator++(){
//今回の場合は最初の位置(m_sereal)か末端(SIZE_MAX)かしか状態がないのでイテレータのm_indexが0より大きくなったら末端に置き換える
m_index++;
if(m_index > 0){ m_index = SIZE_MAX; }
return *this;
}
//後置インクリメントの実装
template<typename T>
MyClassIterator<T> MyClassIterator<T>::operator++(int){
MyClassIterator result = *this;
++m_index;
if(m_index > 0){ m_index = SIZE_MAX; }
return result;
}
//等価演算子の実装(比較内容は同じ位置を示しているかどうか)
template<typename T>
bool MyClassIterator<T>::operator==(const MyClassIterator& iterator){
return ( (m_myCls == iterator.m_myCls) || (m_index == iterator.m_index) );
}
//不等価演算子の実装(等価演算子を否定する)
template<typename T>
bool MyClassIterator<T>::operator!=(const MyClassIterator& iterator){
return !(*this == iterator);
}
/***************************************/
/* MyClassクラスの実装 */
/***************************************/
//begin関数は最初の位置を示すイテレータを作って返す
template<typename T>
iterator MyClass<T>::begin(){ //エラー
return iterator(this,0);
}
//end関数は末端位置(最後の要素の次の位置)を示すイテレータを返す
template<typename T>
iterator MyClass<T>::end(){ //エラー
return iterator();
}
//コンストラクタ群
template<typename T>
MyClass<T>::MyClass(){
m_serial = 0;
}
template<typename T>
MyClass<T>::MyClass(const MyClass& myCls){
m_serial = myCls.m_serial;
}
//m_serialのアクセサ
template<typename T>
T MyClass<T>::getSerial() const {
return m_serial;
}
コンテナであるMyClassクラスの "begin関数" と "end関数"の戻り値の部分で "型指定子がありません"等のエラーが出たので、
調べると、 "typedefだけではなく、typename指定をして型である事を明示する必要がある"という解決策らしい情報を得たので試したのですが、結果は変わらずエラーでした。
肝心の質問ですが、
begin関数、end関数共に戻り値を "iterator" から "MyClassIterator<T>" に変更すると意図通りにコンパイルが通るのは確認しましたが、
何故、typename指定した筈の "iterator" は戻り値の型として認められないのでしょうか?
色々、調べて試したのですが、理由が分かりません。どうかよろしくお願いします。
ちなみに環境は、VisualStudio C++ 2010 です。