CRTP的容器

时间:2011-08-30 04:56:45

标签: c++ templates crtp

我正在削减一些模板编程,我对此非常陌生。我想要实现的是一些包含STL容器的CRTP类。让class A{};作为(编译时)基类的一个例子,在编译时,class B{};class C{};在CRTP样式之后被“派生”。

现在,BC都将包含容器。出于示例的目的,分别为std::vectorstd::set。现在,我想通过公开前向迭代器的begin()end()函数公开这些迭代器。但是,我不想暴露BC内的确切容器,我想为A定义这些函数,以便在调用时为正确的容器<{1}}和B被使用。

这可能吗?现在我的计划是为C创建一个Iterator内部类以及B,它将包含实际的迭代器(一个矢量或一个集合,视情况而定)和委托对它的呼唤。然而,这似乎是很多复制的胶水代码,我怀疑有更好的选择。

我有几个问题:

  1. 如何在CAB中声明内部条款,以便与CRTP配合良好。我需要为CAB复制吗?它可以是C中的空类,我使用专门的实现在AB中屏蔽它们吗?

  2. 如何用更少的胶水和更少的重复来暴露迭代器?

  3. 我不想用像boost这样的外部库创建依赖项,只想坚持使用std。所以我必须自己实施我需要的任何额外的东西。感谢您的帮助。

2 个答案:

答案 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 TWrapperBaseB - TWrapperBC - TWrapperC。另一件事,你并不需要为这个特定的例子提供两个派生类,但我认为你的类BC明显不同,无法在你的程序中证明它。

编辑:忘记在循环中增加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;
}