【问题标题】:Is it possible to get rid of template specialisation to stop recursion?是否可以摆脱模板专业化来停止递归?
【发布时间】:2023-03-17 05:43:02
【问题描述】:

我正在编写自己的容器类,它也提供迭代器。这些迭代器可以被取消引用并显示原始容器的子范围,再次可以获得迭代器。

目前,我有一个模板迭代器类(使用boost::iterator_facade),如果L!=0 取消引用Collection(“范围”),如果L==0 取消引用T&(存储元素)。是否可以将两者结合在一个类中,从而需要更少的重复代码?

template<typename T, int L>
class CollectionIter : public boost::iterator_facade<
        CollectionIter<T,L>, // type it selfe
        Collection<T,L-1>, // value type
        boost::random_access_traversal_tag,
        Collection<T,L-1> > // deref. type
{
public:
    CollectionIter(T* ptr, const std::vector<int>& collectionSize_)
        : pointer(ptr), collectionSize(collectionSize_) { }
    T* element() { return pointer; }
private:
    friend class boost::iterator_core_access;
    bool equal(const CollectionIter<T,L>& other) const { return pointer==other.pointer; }
    auto dereference() const { return Collection<T,L-1>(pointer, collectionSize); }
    void increment() { pointer = pointer + stepsize(); }
    void decrement() { pointer = pointer - stepsize(); }
    void advance(size_t i) { pointer = pointer + i*stepsize(); }
    auto distance_to(const CollectionIter<T,L>& other) { return (other.pointer - pointer)/stepsize(); }

    int stepsize() { return collectionSize.at(L); }

    T* pointer;
    const std::vector<int>& collectionSize;
};

/* Groundlevel Collection: deref returns T& */
template<typename T>
class CollectionIter<T,0> : public boost::iterator_facade<
        CollectionIter<T,0>,
        T,
        boost::random_access_traversal_tag >
{
public:
    CollectionIter(T* ptr, const std::vector<int>& collectionSize_)
        : pointer(ptr), collectionSize(collectionSize_) { assert(stepsize()==1); }
    T* element() { return pointer; }

private:
    friend class boost::iterator_core_access;
    bool equal(const CollectionIter<T,0>& other) const { return pointer==other.pointer; }
    T& dereference() const { return *pointer; }
    void increment() { pointer = pointer + stepsize(); }
    void decrement() { pointer = pointer - stepsize(); }
    void advance(size_t i) { pointer = pointer + i*stepsize(); }
    auto distance_to(const CollectionIter<T,0>& other) { return (other.pointer - pointer)/stepsize(); }

    int stepsize() { return collectionSize.at(0); }

    T* pointer;
    const std::vector<int>& collectionSize;
};

【问题讨论】:

  • 如果不深入了解您的代码,您似乎想在代码中的某处应用std::conditional 以避免重复并仍然获得正确的继承。

标签: c++ templates c++14 template-meta-programming template-specialization


【解决方案1】:

CollectionIter 的两个版本我只看到三个不同之处:

(1) boost::iterator_facade() 继承的类接收不同的参数。您可以按照 Johannes Schaub 的建议使用 std::conditional 解决此问题;像

   public std::conditional< (L > 0U),
              boost::iterator_facade<
                 CollectionIter<T, L>,
                 Collection<T, L-1U>,
                 boost::random_access_traversal_tag,
                 Collection<T, L-1U> >,
              boost::iterator_facade<
                 CollectionIter<T, 0U>,
                 T,
                 boost::random_access_traversal_tag > >

(2) 构造函数中的assert(stepsize()==1); 仅存在于地面 (L == 0U) 版本中。您可以将其修改为

assert( (L > 0U) || (stepsize() == 1) ); 

(3) 递归dereference() 方法在地面版本中确实不同。我不是 SFINAE 的专家,但如果我没记错的话,您可以按如下方式插入两者

  template <int M = L, typename = std::enable_if_t<(M > 0U)>>
  auto dereference () const
   { return Collection<T, L-1U>(pointer, collectionSize); }

  template <int M = L, typename = std::enable_if_t<(M == 0U)>>
  T & dereference () const
   { return *pointer; }

所以全班变成了(对不起:我把L改成了std::size_t

template <typename T, std::size_t L>
class CollectionIter :
   public std::conditional< (L > 0U),
              boost::iterator_facade<
                 CollectionIter<T, L>,
                 Collection<T, L-1U>,
                 boost::random_access_traversal_tag,
                 Collection<T, L-1U> >,
              boost::iterator_facade<
                 CollectionIter<T, 0U>,
                 T,
                 boost::random_access_traversal_tag > >
 {
   public:
      CollectionIter (T * ptr, const std::vector<int> & collectionSize_)
         : pointer(ptr), collectionSize(collectionSize_)
          { assert( (L > 0U) || (stepsize() == 1) ); }

      T* element() { return pointer; }

   private:
      friend class boost::iterator_core_access;

      bool equal (const CollectionIter<T, L> & other) const
       { return pointer==other.pointer; }

      template <int M = L, typename = std::enable_if_t<(M > 0U)>>
      auto dereference () const
       { return Collection<T, L-1U>(pointer, collectionSize); }

      template <int M = L, typename = std::enable_if_t<(M == 0U)>>
      T & dereference () const
       { return *pointer; }

      void increment ()
       { pointer = pointer + stepsize(); }

      void decrement()
       { pointer = pointer - stepsize(); }

      void advance (size_t i)
       { pointer = pointer + i*stepsize(); }

      auto distance_to (const CollectionIter<T, L> & other)
       { return (other.pointer - pointer)/stepsize(); }

      int stepsize()
       { return collectionSize.at(L); }

      T * pointer;

      const std::vector<int> & collectionSize;
 };

【讨论】:

    猜你喜欢
    • 2020-10-13
    • 1970-01-01
    • 1970-01-01
    • 2019-08-19
    • 2011-05-26
    • 2018-07-14
    • 2020-07-18
    • 1970-01-01
    • 2011-05-31
    相关资源
    最近更新 更多