我正在削减一些模板编程,我对此非常陌生。我想要实现的是一些包含STL容器的CRTP类。让class A{};
作为(编译时)基类的一个例子,在编译时,class B{};
和class C{};
在CRTP样式之后被“派生”。
现在,B
和C
都将包含容器。出于示例的目的,分别为std::vector
和std::set
。现在,我想通过公开前向迭代器的begin()
和end()
函数公开这些迭代器。但是,我不想暴露B
和C
内的确切容器,我想为A
定义这些函数,以便在调用时为正确的容器<{1}}和B
被使用。
这可能吗?现在我的计划是为C
创建一个Iterator
内部类以及B
,它将包含实际的迭代器(一个矢量或一个集合,视情况而定)和委托对它的呼唤。然而,这似乎是很多复制的胶水代码,我怀疑有更好的选择。
我有几个问题:
如何在C
,A
和B
中声明内部条款,以便与CRTP配合良好。我需要为C
,A
和B
复制吗?它可以是C
中的空类,我使用专门的实现在A
和B
中屏蔽它们吗?
如何用更少的胶水和更少的重复来暴露迭代器?
我不想用像boost这样的外部库创建依赖项,只想坚持使用std。所以我必须自己实施我需要的任何额外的东西。感谢您的帮助。
答案 0 :(得分:2)
通过CRTP公开迭代器:
template <typename T, typename Iter, typename ConstIter>
struct Base
{
Iter begin() { return static_cast<T*>(this)->begin(); }
Iter end() { return static_cast<T*>(this)->end(); }
ConstIter begin() const { return static_cast<const T*>(this)->begin(); }
ConstIter end() const { return static_cast<const T*>(this)->end(); }
};
struct B : Base<B, std::vector<int>::iterator, std::vector<int>::const_iterator>
{
std::vector<int>::iterator begin() { return container.begin(); }
...
private:
std::vector<int> container;
};
如果要公开更多类型,则将traits类作为模板参数传递给Base
:
template <typename T, typename Traits>
struct Base
{
typename Traits::iterator begin() { ... }
...
};
// For this purpose, vector<int> makes a perfect traits class !
struct B : Base<B, std::vector<int> >
{
std::vector<int>::iterator begin() { ... }
...
};
// Here is an example function taking Base as argument
template <typename T, typename Traits>
void foo(const Base<T, Traits>& x)
{
typename Traits::iterator i = x.begin();
...
}
答案 1 :(得分:1)
如果我理解你,你正在寻找这样的东西。注意,我做了一些简单的构造函数只是为了说明它的工作原理。此外,您的class A
是我的class TWrapperBase
,B
- TWrapperB
,C
- TWrapperC
。另一件事,你并不需要为这个特定的例子提供两个派生类,但我认为你的类B
和C
明显不同,无法在你的程序中证明它。
编辑:忘记在循环中增加lIterSet。
#include <vector>
#include <set>
#include <iostream>
template< typename PType, typename PContainer >
class TWrapperBase
{
public:
typedef PType TType;
typedef PContainer TContainer;
typedef typename TContainer::iterator TIterator;
protected:
TContainer mContainer;
public:
TWrapperBase( const TContainer& pOriginal ) :
mContainer( pOriginal )
{
}
TIterator begin( void )
{
return mContainer.begin();
}
TIterator end( void )
{
return mContainer.end();
}
};
template< typename PType, class PContainer = std::vector< PType > >
class TWrapperB : public TWrapperBase< PType, PContainer >
{
public:
TWrapperB( const TContainer& pOriginal ) :
TWrapperBase( pOriginal )
{
}
};
template< typename PType, class PContainer = std::set< PType > >
class TWrapperC : public TWrapperBase< PType, PContainer >
{
public:
TWrapperC( const TContainer& pOriginal ) :
TWrapperBase( pOriginal )
{
}
};
int main( void )
{
int lInit[] =
{
1, 2, 3
};
std::vector< int > lVec( lInit, lInit + 3 );
std::set< int > lSet( lInit, lInit + 3 );
TWrapperB< int > lB( lVec );
TWrapperC< int > lC( lSet );
std::vector< int >::iterator lIterVec = lB.begin();
std::set< int >::iterator lIterSet = lC.begin();
while( lIterVec < lB.end() )
{
std::cout << "vector: " << *lIterVec << " / set: " << *lIterSet << std::endl;
lIterVec++;
lIterSet++;
}
return 0;
}