How to avoid code duplication implementing const and non-const iterators?

前端 未结 6 1085
借酒劲吻你
借酒劲吻你 2020-11-29 18:30

I\'m implementing a custom container with an STL-like interface. I have to provide a regular iterator and a const iterator. Most of the code for the two versions of the it

6条回答
  •  余生分开走
    2020-11-29 19:10

    Since C++11/14 you can avoid such little helpers an deduce the constness directly from a boolean template.

    constness.h:

    #ifndef ITERATOR_H
    #define ITERATOR_H
    #include 
    #include 
    #include 
    #include 
    
    struct dummy_struct {
      int hello = 1;
      int world = 2;
      dummy_struct() : hello{ 0 }, world{ 1 }{ }
    };
    
    template< class T >
    class iterable {
      public:
        template< bool Const = false >
        class my_iterator {
          public:
            using iterator_category = std::forward_iterator_tag;
            using value_type = T;
            using difference_type = std::ptrdiff_t;
            /* deduce const qualifier from bool Const parameter */
            using reference = typename std::conditional_t< Const, T const &, T & >;
            using pointer = typename std::conditional_t< Const, T const *, T * >;
    
          protected:
            pointer i;
    
          public:
            my_iterator( T* _i ) : i{ reinterpret_cast< pointer >( _i ) } { }
    
            /* SFINAE enables the const dereference operator or the non 
               const variant
               depending on bool Const parameter */          
            template< bool _Const = Const >
            std::enable_if_t< _Const, reference >
            operator*() const {
              std::cout << "Const operator*: ";
              return *i;
            }
    
            template< bool _Const = Const >
            std::enable_if_t< !_Const, reference >
            operator*() {
              std::cout << "Non-Const operator*: ";
              return *i; 
            }
    
            my_iterator & operator++() {
              ++i;
              return *this;
            }
            bool operator!=( my_iterator const & _other ) const {
              return i != _other.i;
            }
    
            bool operator==( my_iterator const & _other ) const {
              return !( *this != _other );
            }   
        };  
    
    
    
      private:
        T* __begin;
        T* __end; 
      public:
        explicit iterable( T* _begin, std::size_t _count ): __begin{ _begin }, __end{ _begin + _count } { std::cout << "End: " << __end << "\n"; }
    
        auto begin()  const { return my_iterator< false >{ __begin }; }
        auto end()    const { return my_iterator< false >{ __end }; }
    
        auto cbegin() const { return my_iterator< true >{ __begin }; }
        auto cend()   const { return my_iterator< true >{ __end }; }
    };
    #endif
    

    This can be used with something like that:

    #include 
    #include 
    #include "constness.h"
    
    int main() {
    
      dummy_struct * data = new dummy_struct[ 5 ];
      for( int i = 0; i < 5; ++i ) {
        data[i].hello = i;
        data[i].world = i+1;
      } 
      iterable< dummy_struct > i( data, 5 );
    
      using iter = typename iterable< dummy_struct >::my_iterator< false >;
      using citer = typename iterable< dummy_struct >::my_iterator< true >;
    
      for( iter it = i.begin(); it != i.end(); ++it  ) {
        std::cout << "Hello: " << (*it).hello << "\n"
                  << "World: " << (*it).world << "\n";
      }
    
      for( citer it = i.cbegin(); it != i.cend(); ++it  ) {
        std::cout << "Hello: " << (*it).hello << "\n"
                  << "World: " << (*it).world << "\n";
      }
      delete[] data;
    
    }
    

提交回复
热议问题