Ответ 1
Вы можете найти следующую статью интересной, поскольку она касается именно той проблемы, которую вы опубликовали: О растяжении между объектно-ориентированным и общим программированием в С++ и какому типе Erasure может сделать об этом
Я использую С# в течение некоторого времени, а возврат к С++ - головная боль. Я пытаюсь получить некоторые из своих практик от С# со мной до С++, но я нахожу некоторое сопротивление, и я был бы рад принять вашу помощь.
Я хотел бы открыть итератор для класса следующим образом:
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;
};
Я пытаюсь что-то, что не проблема? Должен ли я просто typedef std::vector <T> :: итератор? Я надеюсь, что это зависит только от итератора, а не от контейнера-реализации...
Вы можете найти следующую статью интересной, поскольку она касается именно той проблемы, которую вы опубликовали: О растяжении между объектно-ориентированным и общим программированием в С++ и какому типе Erasure может сделать об этом
Это должно делать то, что вы хотите:
typedef typename std::vector<T>::iterator MyIterator;
От Ускоренный С++:
Всякий раз, когда у вас есть тип, например
vector<T>
, который зависит от параметра шаблона, и вы хотите использовать член этого типа, напримерsize_type
, который сам по себе является типом, вы должны предшествовать всему nametypename
, чтобы реализовать реализацию, чтобы обработать имя как тип.
Ранее я сделал следующее, чтобы получить итератор, не зависящий от контейнера. Возможно, это было излишним, поскольку я мог также использовать API, в котором вызывающий абонент переходит в vector<T*>&
, который должен быть заполнен всеми элементами, а затем вызывающий может просто перебирать из вектора напрямую.
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;
}
}
Я не уверен, что вы подразумеваете под "не разоблачением std::vector публично", но действительно, вы можете просто определить свой typedef следующим образом:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator; // To work with constant references
Вы сможете изменить эти typedefs позже, если пользователь ничего не заметит...
Кстати, считается хорошей практикой также выставлять несколько других типов, если вы хотите, чтобы ваш класс вел себя как контейнер:
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
, как предложено в комментариях