4

我正在学习一些模板编程,对此我很陌生。我想要实现的是一些包含 STL 容器的 CRTP 类。让我们class A{};作为(编译时)基类的示例,在编译时遵循 CRTP 样式从该基类“派生”class B{};和“派生”。class C{};

现在两者都BC包含容器。为了示例的目的,让它分别为 astd::vector和 a std::set。现在,我想通过 abegin()和一个end()公开前向迭代器的函数公开这些迭代器。但是,我不想暴露里面的确切容器是什么BC并且我想为 定义这些函数A,以便在调用时正确的一个用于B并被C使用。

这可能吗 ?现在我的计划是有一个Iterator内部类,它将包含(BC情况而定的向量或集合)的实际迭代器并将调用委托给它。然而,这似乎是很多复制的胶水代码,我怀疑有更好的选择。

我有一些问题:

  1. 如何在 中声明内部 clases A,以便它与 CRTP 很好地配合BC我需要为 和 复制ABC?它可以是一个空类,我用专门的实现A将它们掩盖起来吗?BC

  2. 如何使用更少的胶水和更少的重复来公开迭代器?

我不想与外部库(如 boost)创建依赖关系,并且只想坚持使用 std。所以我必须自己实现我需要的任何额外功能。感谢所有的帮助。

4

2 回答 2

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;
};

如果您有更多类型要公开,则将特征类作为模板参数传递给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();
    ...
}
于 2011-08-30T10:13:47.370 回答
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;
}
于 2011-08-30T10:05:32.920 回答