How to implement standard iterators in class

前端 未结 3 1567
温柔的废话
温柔的废话 2021-02-06 04:40

I have classes which are usually using standard containers as underlying fields. For example, I have a class

template 
class Vec_3D
{
public:
          


        
3条回答
  •  无人共我
    2021-02-06 05:35

    std::iterator is (was) a helper type to define the typedefs that a typical iterator requires. These typedefs within the class in turn make std::iterator_traits work with your iterator.

    It does not, however, actually implement the required operations for you.

    It was deprecated, because the std committee didn't like specifying that standard iterators had to have those typedefs, and writing the typedefs was not much bulkier than figuring out what arguments to pass to the std::iterator template.

    The easy thing to do here is to just steal your underlying container's iterator. This makes your abstraction leak, but it is efficient and easy.

    template 
    struct Vec_3D {
      using container=std::array;
      using iterator=typename container::iterator;
      using const_iterator=typename container::const_iterator;
    
      iterator begin() { return vec.begin(); }
      iterator end() { return vec.end(); }
      const_iterator begin() const { return vec.begin(); }
      const_iterator end() const { return vec.end(); }
    private:
      /* ... */
      container vec;
      /* ... */
    };
    

    If you don't want to expose your underlying container type, if you are willing to guarantee your underlying container is a contiguous buffer you can do:

    template 
    struct Vec_3D {
      using iterator=T*;
      using const_iterator=T const*;
    
      iterator begin() { return vec.data(); }
      iterator end() { return vec.data()+vec.size(); }
      const_iterator begin() const { return vec.data(); }
      const_iterator end() const { return vec.data()+vec.size(); }
    private:
      /* ... */
      std::array vec;
      /* ... */
    };
    

    as pointers are valid iterators.

    If you find you are writing this "I am a modified container" boilerplate too much, you can automate it:

    template
    struct container_wrapper {
      using container=Container;
    
      using iterator=typename container::iterator;
      using const_iterator=typename container::const_iterator;
    
      iterator begin() { return m_data.begin(); }
      iterator end() { return m_data.end(); }
      const_iterator begin() const { return m_data.begin(); }
      const_iterator end() const { return m_data.end(); }
    protected:
      Container m_data;
    };
    

    and then

    template 
    class Vec_3D:private container_wrapper> {
      // ...
    };
    

    but even that might be a bit much, why not just:

    template 
    class Vec_3D:public std::array {
      // ...
    };
    

    It is true that deleting Vec_3D through a pointer to base is undefined behavior, but who deletes pointers to standard containers?

    If this worries you:

    template 
    class Vec_3D: private std::array {
      using container = std::array;
      using container::begin();
      using container::end();
      // ...
    };
    

    lets you inherit privately, then bring certain operations back into scope.

提交回复
热议问题