CRTP'ed 容器

CRTP'ed Containers

本文关键字:ed 容器 CRTP      更新时间:2023-10-16

我正在一些模板编程中咬牙切齿,我对此非常陌生。我要实现的是几个包含 STL 容器的 CRTP 类。让我们class A{};作为(编译时(基类的示例,class B{};class C{};在编译时按照 CRTP 样式"派生"自该基类。

现在,BC都将包含容器。出于示例的目的,请分别将其设为std::vectorstd::set。现在,我想通过一个begin()和一个公开前向迭代器的end()函数来公开这些迭代器。但是,我不想公开 BC 内部的确切容器是什么,我想为 A 定义这些函数,以便在调用时使用正确的 BC 函数。

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

我有几个问题:

  1. 如何在 ABC 中声明内链,以便它与 CRTP 很好地配合使用。我需要复制它ABC吗?它可以在A中是一个空类,我用专门的实现BC屏蔽它们吗?

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

我不想创建与 boost 等外部库的依赖项,只想坚持使用 std。所以我必须自己实现我需要的任何额外内容。感谢您的所有帮助。

也通过 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();
    ...
}

如果我理解你的意思,你正在寻找这样的东西。请注意,我做了一些简单的构造函数只是为了说明它的工作原理。另外,你的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;
}