使用されているコンテナを公開せずにイテレータを公開するにはどうすればよいですか?
-
03-07-2019 - |
質問
私はしばらくの間C#を使用していましたが、C ++に戻るのは頭痛の種です。私はC#からC ++に自分のプラクティスの一部を取り込もうとしていますが、多少の抵抗を感じており、喜んであなたの助けを受け入れます。
次のようなクラスのイテレータを公開したい:
template <class T>
class MyContainer
{
public:
// Here is the problem:
// typedef for MyIterator without exposing std::vector publicly?
MyIterator Begin() { return mHiddenContainerImpl.begin(); }
MyIterator End() { return mHiddenContainerImpl.end(); }
private:
std::vector<T> mHiddenContainerImpl;
};
私は問題ではないことを試みていますか? std :: vector <!> lt;をtypedefするだけです。 T <!> gt; :: iterator?実装コンテナではなく、イテレータに依存することを期待しています...
解決
次の記事は、投稿した問題に正確に対応しているため、興味深いと思うかもしれません:テンションについてC ++でのオブジェクト指向プログラミングと汎用プログラミングと、それに対して型消去ができることとの間
他のヒント
以前は次のことを行っていたため、コンテナに依存しないイテレータを取得しました。呼び出し元がvector<T*>&
を渡すAPIを使用することもできたので、これはやり過ぎかもしれません。このAPIには、すべての要素を設定し、呼び出し元はベクターから直接反復することができます。
template <class T>
class IterImpl
{
public:
virtual T* next() = 0;
};
template <class T>
class Iter
{
public:
Iter( IterImpl<T>* pImpl ):mpImpl(pImpl) {};
Iter( Iter<T>& rIter ):mpImpl(pImpl)
{
rIter.mpImpl = 0; // take ownership
}
~Iter() {
delete mpImpl; // does nothing if it is 0
}
T* next() {
return mpImpl->next();
}
private:
IterImpl<T>* mpImpl;
};
template <class C, class T>
class IterImplStl : public IterImpl<T>
{
public:
IterImplStl( C& rC )
:mrC( rC ),
curr( rC.begin() )
{}
virtual T* next()
{
if ( curr == mrC.end() ) return 0;
typename T* pResult = &*curr;
++curr;
return pResult;
}
private:
C& mrC;
typename C::iterator curr;
};
class Widget;
// in the base clase we do not need to include widget
class TestBase
{
public:
virtual Iter<Widget> getIter() = 0;
};
#include <vector>
class Widget
{
public:
int px;
int py;
};
class Test : public TestBase
{
public:
typedef std::vector<Widget> WidgetVec;
virtual Iter<Widget> getIter() {
return Iter<Widget>( new IterImplStl<WidgetVec, Widget>( mVec ) );
}
void add( int px, int py )
{
mVec.push_back( Widget() );
mVec.back().px = px;
mVec.back().py = py;
}
private:
WidgetVec mVec;
};
void testFn()
{
Test t;
t.add( 3, 4 );
t.add( 2, 5 );
TestBase* tB = &t;
Iter<Widget> iter = tB->getIter();
Widget* pW;
while ( pW = iter.next() )
{
std::cout << "px: " << pW->px << " py: " << pW->py << std::endl;
}
}
これはあなたが望むことをするはずです:
typedef typename std::vector<T>::iterator MyIterator;
Accelerated C ++ から:
テンプレートパラメータに依存する
vector<T>
などの型があり、それ自体が型であるsize_type
などのその型のメンバーを使用する場合は、全体を優先する必要があります。名前をtypename
で指定して、名前をタイプとして扱うことを実装に知らせます。
<!> quot; std :: vectorを公開していないという意味がわかりません<!> quot;しかし、実際には、そのようにtypedefを定義するだけです:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator; // To work with constant references
これらのtypedefは、ユーザーが気付かないうちに後で変更できます...
ところで、クラスをコンテナとして動作させたい場合は、いくつかの他の型も公開することをお勧めします:
typedef typename std::vector<T>::size_type size_type;
typedef typename std::vector<T>::difference_type difference_type;
typedef typename std::vector<T>::pointer pointer;
typedef typename std::vector<T>::reference reference;
そしてクラスで必要な場合:
typedef typename std::vector<T>::const_pointer const_pointer;
typedef typename std::vector<T>::const_reference const_reference;
これらのすべてのtypedefの意味は次のとおりです。ベクターのSTLドキュメント
編集:コメントで提案されているようにtypename
を追加しました